Skip to content

Commit

Permalink
src: explore: add --show-context flag
Browse files Browse the repository at this point in the history
The idea was to expand kw explore to show extra context
after matching a string. This has been achieved by adding
a new -C | --show-context flag which accepts an integer
argument. The default value for this arg will be 3.
The functionality is implemented by using native
features of grep and git grep commands, to avoid adding new
dependencies.

tests: unit: explore_test: Added test cases for --show-context
src: bash_autocomplete: Updated bash completions for kw explore
src: _kw: updated zsh completions for kw explore
documentation: man: features: kw-explore: updated man page and
added examples for kw explore

Closes: kworkflow#1052

Signed-off-by: Sahil Sagwekar <[email protected]>
Reviewed-by: Rodrigo Siqueira <[email protected]>
Signed-off-by: Rodrigo Siqueira <[email protected]>
  • Loading branch information
sahil-sagwekar2652 authored and rodrigosiqueira committed May 20, 2024
1 parent 328449c commit 1f050b5
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 20 deletions.
20 changes: 19 additions & 1 deletion documentation/man/features/kw-explore.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ kw-explore - Explore folder
SYNOPSIS
========
*kw* (*e* | *explore*) [(-l | \--log) | (-g | \--grep) | (-a | \--all) | \--verbose]
[(-c | \--only-source) | (-H | \--only-header)] <expr>
[(-c | \--only-source) | (-H | \--only-header)] [(-C[<num>] | \--show-context[=<num>])] <expr>
[-p] [<dir> | <file>]

DESCRIPTION
Expand Down Expand Up @@ -45,5 +45,23 @@ OPTIONS
-H | \--only-header:
With this option, it is possible to show only the results from the header.

-C[<num>] | \--show-context[=<num>]:
Show <num> lines of additional context above and below the matched line.
If <num> is not specified, the default value of 3 will be used.

\--verbose:
Verbose mode allows the user to see the commands executed under the hood.

EXAMPLES
========
To show matched line with context using long-form flag::

kw explore --show-context=5 search_string

To show matched line with context using short flag::

kw explore -C5 search_string

Search through all tracked and untracked files, default value of 3 will be used for context::

kw explore -C --all search_string
1 change: 1 addition & 0 deletions src/_kw
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ _kw_explore()
'(-a --all -l --log -g --grep)'{-a,--all}'[search for all matches in files under or not git management]' \
'(-c --only-source -H --only-header)'{-c,--only-source}'[show only results from the source]' \
'(-H --only-header -c --only-source)'{-H,--only-header}'[show only results from the header]' \
'(-C --show-context)'{-C-,--show-context=-}'[set the context value]' \
'1: : ' \
'2: :_files'
}
Expand Down
2 changes: 1 addition & 1 deletion src/bash_autocomplete.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function _kw_autocomplete()

kw_options['remote']='--add --remove --rename --list --global --set-default --verbose'

kw_options['explore']='--log --grep --all --only-header --only-source --exactly --verbose'
kw_options['explore']='--log --grep --all --only-header --only-source --exactly --show-context --verbose'
kw_options['e']="${kw_options['explore']}"

kw_options['pomodoro']='--set-timer --check-timer --show-tags --tag --description --help --verbose'
Expand Down
49 changes: 37 additions & 12 deletions src/explore.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function explore_main()
local flag
local search
local path
local context
local ret

if [[ "$1" =~ -h|--help ]]; then
Expand All @@ -31,6 +32,7 @@ function explore_main()
flag="${options_values['TEST_MODE']:-'SILENT'}"
search="${options_values['SEARCH']}"
path="${options_values['PATH']:-'.'}"
context="${options_values['CONTEXT']:-0}"

[[ -n "${options_values['VERBOSE']}" ]] && flag='VERBOSE'

Expand All @@ -48,19 +50,19 @@ function explore_main()

if [[ "${options_values['TYPE']}" -eq 2 ]]; then
# Use GNU GREP
explore_files_gnu_grep "$search" "$path" "$flag"
explore_files_gnu_grep "$search" "$path" "$context" "$flag"
return
fi

if [[ "${options_values['TYPE']}" -eq 3 ]]; then
# Search in directories controlled or not by git
explore_all_files_git "$search" "$path" "$flag"
explore_all_files_git "$search" "$path" "$context" "$flag"
return
fi

if [[ -z "${options_values['TYPE']}" ]]; then
# Search in files under git control
explore_files_under_git "$search" "$path" "$flag"
explore_files_under_git "$search" "$path" "$context" "$flag"
return
fi
}
Expand All @@ -75,8 +77,8 @@ function explore_main()
# This function also set options_values
function parse_explore_options()
{
local long_options='log,grep,all,only-header,only-source,exactly,verbose'
local short_options='l,g,a,H,c'
local long_options='log,grep,all,only-header,only-source,exactly,verbose,show-context::'
local short_options='l,g,a,H,c,C::'
local options

if [[ "$#" -eq 0 ]]; then
Expand All @@ -97,6 +99,7 @@ function parse_explore_options()
options_values['TYPE']=''
options_values['SCOPE']=''
options_values['EXACTLY']=''
options_values['CONTEXT']=''
options_values['VERBOSE']=''

eval "set -- $options"
Expand Down Expand Up @@ -158,6 +161,24 @@ function parse_explore_options()
;;
--verbose)
options_values['VERBOSE']=1
shift
;;
--show-context | -C)
if [[ -n "${options_values['CONTEXT']}" ]]; then
options_values['ERROR']='Invalid arguments: Multiple context values!'
return 22 # EINVAL
fi

if [[ ! "$2" ]]; then
options_values['CONTEXT']=3
elif [[ ! "$2" =~ ^[0-9]+$ ]]; then
options_values['ERROR']='Context value must be a non-negative integer!'
return 22 # EINVAL
else
options_values['CONTEXT']="$2"
shift
fi

shift
;;
--) # End of options, beginning of arguments
Expand Down Expand Up @@ -196,7 +217,7 @@ function explore_git_log()

flag=${flag:-'SILENT'}

cmd_manager "$flag" "git log --grep='$search_string' $path"
cmd_manager "$flag" "git log --grep='${search_string}' ${path}"
}

# This function searches string in files under git control.
Expand All @@ -209,11 +230,12 @@ function explore_files_under_git()
{
local regex="$1"
local path="$2"
local flag="$3"
local context="$3"
local flag="$4"

flag=${flag:-'SILENT'}

cmd_manager "$flag" "git grep -e '$regex' -nI $path"
cmd_manager "$flag" "git grep --context ${context} -e '${regex}' --line-number -I ${path}"
}

# This function uses git grep tool to search string in files under or not git
Expand All @@ -228,11 +250,12 @@ function explore_all_files_git()
{
local regex="$1"
local path="$2"
local flag="$3"
local context="$3"
local flag="$4"

flag=${flag:-'SILENT'}

cmd_manager "$flag" "git grep --no-index -e '$regex' -nI $path"
cmd_manager "$flag" "git grep --no-index --context ${context} -e '${regex}' --line-number -I ${path}"
}

# This function allows the use of gnu grep utility to manages the search for
Expand All @@ -246,11 +269,12 @@ function explore_files_gnu_grep()
{
local regex="$1"
local path="$2"
local flag="$3"
local context="$3"
local flag="$4"

flag=${flag:-'SILENT'}

cmd_manager "$flag" "grep --color -nrI $path -e '$regex'"
cmd_manager "$flag" "grep --color --line-number --recursive -I ${path} --context ${context} -e '${regex}'"
}

function explore_help()
Expand All @@ -267,5 +291,6 @@ function explore_help()
' explore,e --all,-a <string> - Search for all <string> match under or not of git management' \
' explore,e --only-source,-c <string> - Search for all <string> in source files' \
' explore,e --only-header,-H <string> - Search for all <string> in header files' \
' explore,e --show-context[=<num>],-C[<num>] <string> - Print <num> lines of output context (default: 3)' \
' explore,e --verbose - Show a detailed output'
}
87 changes: 81 additions & 6 deletions tests/unit/explore_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,14 @@ function test_explore_files_under_git_repo()
assertEquals "($LINENO)" "$MSG_OUT" "$output"

output=$(explore_main 'GNU grep' '.' 'TEST_MODE')
expected_result="git grep -e 'GNU grep' -nI ."
expected_result="git grep --context 0 -e 'GNU grep' --line-number -I ."
assertEquals "($LINENO)" "$expected_result" "$output"

# Test for non zero context value
output=$(explore_main --show-context=5 'GNU grep' '.' 'TEST_MODE')
expected_result="git grep --context 5 -e 'GNU grep' --line-number -I ."
assertEquals "(${LINENO})" "$expected_result" "$output"

# Test if search only in files under git control
cp "$current_path/tests/unit/samples/grep_check.c" ./
MSG_OUT='GNU grep'
Expand All @@ -82,13 +87,13 @@ function test_explore_files_under_git_repo()

# Test only-source and only-header
MSG_OUT='3'
output=$(explore_main 'camelCase' | wc -l)
output=$(explore_main 'camelCase' | wc --lines)
assertEquals "($LINENO)" "$MSG_OUT" "$output"
MSG_OUT='2'
output=$(explore_main -c 'camelCase' | wc -l)
output=$(explore_main -c 'camelCase' | wc --lines)
assertEquals "($LINENO)" "$MSG_OUT" "$output"
MSG_OUT='1'
output=$(explore_main -H 'camelCase' | wc -l)
output=$(explore_main -H 'camelCase' | wc --lines)
assertEquals "($LINENO)" "$MSG_OUT" "$output"

cd "$current_path" || {
Expand Down Expand Up @@ -133,7 +138,11 @@ function test_explore_grep()
assertEquals "($LINENO)" '.git' "$output"

output=$(explore_main --grep 'GNU grep' '.' 'TEST_MODE')
expected_result="grep --color -nrI . -e 'GNU grep'"
expected_result="grep --color --line-number --recursive -I . --context 0 -e 'GNU grep'"
assertEquals "(${LINENO})" "$expected_result" "$output"

output=$(explore_main --grep --show-context=5 'GNU grep' '.' 'TEST_MODE')
expected_result="grep --color --line-number --recursive -I . --context 5 -e 'GNU grep'"
assertEquals "($LINENO)" "$expected_result" "$output"

cd "$current_path" || {
Expand All @@ -153,7 +162,11 @@ function test_explore_git()
}

output=$(explore_main --all 'GNU grep' '.' 'TEST_MODE')
expected_result="git grep --no-index -e 'GNU grep' -nI ."
expected_result="git grep --no-index --context 0 -e 'GNU grep' --line-number -I ."
assertEquals "(${LINENO})" "$expected_result" "$output"

output=$(explore_main --all --show-context=5 'GNU grep' '.' 'TEST_MODE')
expected_result="git grep --no-index --context 5 -e 'GNU grep' --line-number -I ."
assertEquals "($LINENO)" "$expected_result" "$output"

# Test if the search ignores files in .git
Expand All @@ -172,6 +185,47 @@ function test_explore_git()
}
}

function test_explore_context()
{
local -r current_path="$PWD"
local expected_context='3'
local expected_match='avoid'
local msg_out='7'

cd "$SHUNIT_TMPDIR" || {
fail "(${LINENO}) It was not possible to move to temporary directory"
return
}

# Check the number of output lines
output=$(explore_main --show-context=3 'avoid' codestyle_error.c | wc --lines)
assertEquals "(${LINENO})" "$msg_out" "$output"

output=$(explore_main --show-context="$expected_context" "$expected_match" codestyle_error.c)

# Check if the expected match and context lines are present in the output
assert_substring_match 'Expected match not found!' "${LINENO}" "${expected_match}" "$output"

# Check context lines below the match
for ((i = 1; i <= expected_context; i++)); do
CONTEXT_LINE=$((i + 4)) # Assuming match is on line 4
CONTEXT_LINE_CONTENT=$(printf '%s' "$output" | head -n "${CONTEXT_LINE}" | tail --lines 1)
assert_line_match "Context line ${CONTEXT_LINE} below match" "$CONTEXT_LINE_CONTENT" "$output"
done

# Check context lines above the match
for ((i = 1; i <= expected_context; i++)); do
CONTEXT_LINE=$((4 - i)) # Assuming match is on line 4
CONTEXT_LINE_CONTENT=$(printf '%s' "$output" | head -n ${CONTEXT_LINE} | tail -n 1)
assert_line_match "Context line ${CONTEXT_LINE} above match" "$CONTEXT_LINE_CONTENT" "$output"
done

cd "$current_path" || {
fail "(${LINENO}) It was not possible to move back from temp directory"
return
}
}

function test_parse_explore_options()
{
# Expected behaviour
Expand Down Expand Up @@ -236,6 +290,20 @@ function test_parse_explore_options()
assertEquals "($LINENO)" '0' "$ret"
assertEquals "($LINENO)" 'HEADER' "${options_values['SCOPE']}"

unset options_values
declare -gA options_values
parse_explore_options -C
ret="$?"
assertEquals "(${LINENO})" '0' "$ret"
assertEquals "(${LINENO})" '3' "${options_values['CONTEXT']}"

unset options_values
declare -gA options_values
parse_explore_options --show-context=5
ret="$?"
assertEquals "(${LINENO})" '0' "$ret"
assertEquals "(${LINENO})" '5' "${options_values['CONTEXT']}"

# Others
parse_explore_options --logljkl
ret="$?"
Expand Down Expand Up @@ -266,6 +334,13 @@ function test_parse_explore_options()
assertEquals "($LINENO)" '22' "$ret"
assertEquals "($LINENO)" 'Invalid arguments: Multiple search type!' "${options_values['ERROR']}"

unset options_values
declare -gA options_values
parse_explore_options --show-context=invalid
ret="$?"
assertEquals "($LINENO)" '22' "$ret"
assertEquals "($LINENO)" 'Context value must be a non-negative integer!' "${options_values['ERROR']}"

parse_explore_options main
ret="$?"
assertEquals "($LINENO)" '0' "$ret"
Expand Down

0 comments on commit 1f050b5

Please sign in to comment.