From 51fcea7ce08654dfc6eff70b26e59ec6a1aa7a1d Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 3 Feb 2020 23:25:20 +1100 Subject: [PATCH 1/8] rc lint: Add a lint-selections command to lint part of a buffer. Fixes #2302, #3336. Addresses parts of #3155. Changes include: - New `lint-selections` command that only lints the current selections, and allows a custom lint command. - New `lint-buffer` command that always lints the whole buffer with the linter specified in the lintcmd option. - `lint` alias for `lint-buffer`, for backwards compatibility. - Errors and warnings are now shown in the Error and Information faces, not hard-coded red and yellow. - Error and warning flags now use "!" and "?" symbols respectively, instead of a unicode block, so they can still be distinguished in a monochrome colour-scheme or by colour-blind users. - An error flag on a given line always takes precedence over a warning. - All messages for the same line are collected into a multi-line message. - We no longer escape tildes in messages, since that change was added in commit ae339dc (2016) when we started using `%~~` to quote messages. We stopped using `%~~` in commit 1a2eecd (2018). - Anything the linter writes to stderr is logged to the *debug* buffer, not lost. - If the linter writes to stderr, an error is shown to the user instead of the usual error/warning count. - The `lint_errors` hidden option is replaced by `lint_messages`, because it contains warnings as well as errors. - `lint-next-error` renamed to `lint-next-message`, and `lint-previous-error` renamed to `lint-previous-message` for the same reason. - New `lint-next-error` and `lint-previous-error` aliases, for backwards compatibility. - `lint-next-message` and `lint-previous-message` show the message they jump to. - Where `lint_errors` was a range-specs option, `lint_messages` is a line-specs option to keep things simpler. This means lint-next-message and lint-previous-message no longer jump to a specific column. --- rc/tools/lint.kak | 446 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 350 insertions(+), 96 deletions(-) diff --git a/rc/tools/lint.kak b/rc/tools/lint.kak index a0accd08..63fca562 100644 --- a/rc/tools/lint.kak +++ b/rc/tools/lint.kak @@ -1,113 +1,339 @@ -declare-option -docstring %{ - shell command to which the path of a copy of the current buffer will be passed - The output returned by this command is expected to comply with the following format: - {filename}:{line}:{column}: {kind}: {message} -} str lintcmd +declare-option \ + -docstring %{ + The shell command used by lint-buffer and lint-selections. + + It will be given the path to a file containing the text to be + linted, and must produce output in the format: + + {filename}:{line}:{column}: {kind}: {message} + + If the 'kind' field contains 'error', the message is treated + as an error, otherwise it is assumed to be a warning. + } \ + str lintcmd declare-option -hidden line-specs lint_flags -declare-option -hidden range-specs lint_errors +declare-option -hidden line-specs lint_messages declare-option -hidden int lint_error_count declare-option -hidden int lint_warning_count -define-command lint -docstring 'Parse the current buffer with a linter' %{ - evaluate-commands %sh{ - if [ -z "${kak_opt_lintcmd}" ]; then - echo 'fail The `lintcmd` option is not set' - exit 1 - fi +define-command \ + -hidden \ + -params 1 \ + -docstring %{ + lint-cleaned-selections : Check each selection with . + Assumes selections all have anchor before cursor, and that + %val{selections} and %val{selections_desc} are in the same order. + } \ + lint-cleaned-selections \ +%{ + # Clear the current contents of the various options. + set-option buffer lint_flags %val{timestamp} + set-option buffer lint_messages %val{timestamp} + set-option buffer lint_error_count 0 + set-option buffer lint_warning_count 0 + + # Create a temporary directory to keep all our state. + evaluate-commands %sh{ + # This is going to come in handy later. + kakquote() { + printf "'" + printf "%s" "$*" | sed "s/'/''/g" + printf "'" + } + + # Before we clobber our arguments, + # let's record the lintcmd we were given. + lintcmd="$1" + + # Some linters care about the name or extension + # of the file being linted, so we'll store the text we want to lint + # in a file with the same name as the original buffer. filename="${kak_buffile##*/}" + # A directory to keep all our temporary data. dir=$(mktemp -d "${TMPDIR:-/tmp}"/kak-lint.XXXXXXXX) - mkfifo "$dir"/fifo - printf '%s\n' "evaluate-commands -no-hooks write -sync $dir/${filename}" + # A fifo to send the results back to a Kakoune buffer. + # FIXME: Should we put the lint output in toolsclient? + mkfifo "$dir"/fifo printf '%s\n' "evaluate-commands -draft %{ - edit! -fifo $dir/fifo -debug *lint-output* + edit! -fifo $(kakquote "$dir/fifo") -debug *lint-output* set-option buffer filetype make set-option buffer make_current_error_line 0 - hook -always -once buffer BufCloseFifo .* %{ nop %sh{ rm -r '$dir' } } }" + # Write all the selection descriptions to files. + eval set -- "$kak_quoted_selections_desc" + i=0 + for desc; do + mkdir -p "$dir"/sel-"$i" + printf "%s" "$desc" > "$dir"/sel-$i/desc + i=$(( i + 1 )) + done + + # Write all the selection contents to files. + eval set -- "$kak_quoted_selections" + i=0 + for text; do + # The selection text needs to be stored in a subdirectory, + # so we can be sure the filename won't clash with one of ours. + mkdir -p "$dir"/sel-"$i"/text/ + printf "%s" "$text" > "$dir"/sel-$i/text/"$filename" + i=$(( i + 1 )) + done + + # We do redirection trickiness to record stderr from + # this background task and route it back to Kakoune, + # but shellcheck isn't a fan. + # shellcheck disable=SC2094 ({ # do the parsing in the background and when ready send to the session - eval "$kak_opt_lintcmd '$dir'/${filename}" | sort -t: -k2,2 -n > "$dir"/stderr + for selpath in "$dir"/sel-*; do + # Read in the line and column offset of this selection. + IFS=".," read -r start_line start_byte _ < "$selpath"/desc + + # Run the linter, and record the exit-code. + eval "$lintcmd '$selpath/text/$filename'" | + sort -t: -k2,2 -n | + awk \ + -v line_offset=$(( start_line - 1 )) \ + -v first_line_byte_offset=$(( start_byte - 1 )) \ + ' + BEGIN { OFS=":"; FS=":" } + + /:[1-9][0-9]*:[1-9][0-9]*:/ { + $1 = ENVIRON["kak_bufname"] + if ( $2 == 1 ) { + $3 += first_line_byte_offset + } + $2 += line_offset + print $0 + } + ' >>"$dir"/result + done + + # Load all the linter messages into Kakoune options. + # Yes, shellcheck, we do want line-continuation backslashes + # inside the string. + # shellcheck disable=SC1004 + awk -v file="$kak_buffile" -v client="$kak_client" ' + function kakquote(text) { + # \x27 is apostrophe, escaped for shell-quoting reasons. + gsub(/\x27/, "\x27\x27", text) + return "\x27" text "\x27" + } - # Flags for the gutter: - # stamp l3|{red}█ l11|{yellow}█ - # Contextual error messages: - # stamp 'l1.c1,l1.c1|kind:message' 'l2.c2,l2.c2|kind:message' - awk -F: -v file="$kak_buffile" -v stamp="$kak_timestamp" -v client="$kak_client" ' BEGIN { + OFS=":" + FS=":" error_count = 0 warning_count = 0 } - /:[1-9][0-9]*:[1-9][0-9]*: ([Ff]atal )?[Ee]rror/ { - flags = flags " " $2 "|{red}█" - error_count++ - } + /:[1-9][0-9]*:[1-9][0-9]*:/ { - if ($4 !~ /[Ee]rror/) { - flags = flags " " $2 "|{yellow}█" + # Remember that an error or a warning occurs on this line.. + if ($4 ~ /[Ee]rror/) { + # We definitely have an error on this line. + flags_by_line[$2] = "{Error}!" + error_count++ + } else if (flags_by_line[$2] ~ /Error/) { + # We have a warning on this line, + # but we already have an error, so do nothing. + warning_count++ + } else { + # We have a warning on this line, + # and no previous error. + flags_by_line[$2] = "{Information}?" warning_count++ } - } - /:[1-9][0-9]*:[1-9][0-9]*:/ { - kind = substr($4, 2) - error = $2 "." $3 "," $2 "." $3 "|" kind - msg = "" - # fix case where $5 is not the last field because of extra colons in the message + + # The message starts with the severity indicator. + msg = substr($4, 2) + + # fix case where $5 is not the last field + # because of extra colons in the message for (i=5; i<=NF; i++) msg = msg ":" $i + + # Mention the column where this problem occurs, + # so that information is not lost. + msg = msg "(col " $3 ")" + + # FIXME: I *think* this line is left over from a time + # when Kakoune used pipes to delimit items in a list + # option. If so, it is entirely useless now... but I + # am not 100% sure. gsub(/\|/, "\\|", msg) - gsub("'\''", "'"''"'", msg) - error = error msg " (col " $3 ")" - errors = errors " '\''" error "'\''" + + if ($2 in messages_by_line) { + # We already have a message on this line, + # so append our new message. + messages_by_line[$2] = messages_by_line[$2] "\n" msg + } else { + # A brand-new message on this line. + messages_by_line[$2] = msg + } } + END { - print "set-option \"buffer=" file "\" lint_flags " stamp flags - gsub("~", "\\~", errors) - print "set-option \"buffer=" file "\" lint_errors " stamp errors - print "set-option \"buffer=" file "\" lint_error_count " error_count - print "set-option \"buffer=" file "\" lint_warning_count " warning_count - print "evaluate-commands -client " client " lint-show-counters" - } - ' "$dir"/stderr | kak -p "$kak_session" + for (line in flags_by_line) { + flag = flags_by_line[line] - cut -d: -f2- "$dir"/stderr | awk -v bufname="${kak_bufname}" ' - /^[1-9][0-9]*:[1-9][0-9]*:/ { - print bufname ":" $0 - } - ' > "$dir"/fifo + print "set-option -add " \ + kakquote("buffer=" file) " " \ + "lint_flags " \ + kakquote(line "|" flag) + } - } & ) >/dev/null 2>&1 >>\n" + # FIXME: When #3254 is fixed, this can become a "fail" + printf "eval -client %s echo -markup {Error}%s\n" \ + "$kak_client" \ + "lint failed, see *debug* for details" + else + # No errors detected, show the results. + printf "eval -client %s lint-show-counters" \ + "$kak_client" + fi | kak -p "$kak_session" + + # We are done here. Send the results to Kakoune, + # and clean up. + cat "$dir"/result > "$dir"/fifo + rm -rf "$dir" + + } & ) >"$dir"/stderr 2>&1 ]: Check each selection with a linter. + + Switches: + -command Use the given linter. + If not given, the lintcmd option is used. + } \ + lint-selections \ +%{ + evaluate-commands -draft %{ + # Make sure all the selections are "forward" (anchor before cursor) + execute-keys + + # Make sure the selections are in document order. + evaluate-commands %sh{ + printf "select " + printf "%s\n" "$kak_selections_desc" | + tr ' ' '\n' | + sort -n -t. | + tr '\n' ' ' + } + + evaluate-commands %sh{ + # This is going to come in handy later. + kakquote() { + printf "'" + printf "%s" "$*" | sed "s/'/''/g" + printf "'" + } + + if [ "$1" = "-command" ]; then + if [ -z "$2" ]; then + echo 'fail -- -command option requires a value' + exit 1 + fi + lintcmd="$2" + elif [ -n "$1" ]; then + echo "fail -- Unrecognised parameter $(kakquote "$1")" + exit 1 + elif [ -z "${kak_opt_lintcmd}" ]; then + echo 'fail The lintcmd option is not set' + exit 1 + else + lintcmd="$kak_opt_lintcmd" + fi + + printf '%s\n' "lint-cleaned-selections $(kakquote "$lintcmd")" + } + } +} + +define-command \ + -docstring %{ + lint-buffer: Check the current buffer with a linter. + + Set the lintcmd option to control which linter is used. + } \ + lint-buffer \ +%{ + evaluate-commands -draft %{ + execute-keys '%' + lint-cleaned-selections %opt{lintcmd} + } +} + +alias global lint lint-buffer + define-command -hidden lint-show %{ - update-option buffer lint_errors + update-option buffer lint_messages evaluate-commands %sh{ - eval "set -- ${kak_quoted_opt_lint_errors}" - shift + # This is going to come in handy later. + kakquote() { + printf "'" + printf "%s" "$*" | sed "s/'/''/g" + printf "'" + } - s="" - for i in "$@"; do - s="${s} -${i}" + eval set -- "${kak_quoted_opt_lint_messages}" + shift # skip the timestamp + + while [ $# -gt 0 ]; do + lineno=${1%%|*} + msg=${1#*|} + + if [ "$lineno" -eq "$kak_cursor_line" ]; then + printf "info -anchor %d.%d %s\n" \ + "$kak_cursor_line" \ + "$kak_cursor_column" \ + "$(kakquote "$msg")" + break + fi + shift done - - printf %s\\n "${s}" | awk -v line="${kak_cursor_line}" \ - -v column="${kak_cursor_column}" \ - "/^${kak_cursor_line}\./"' { - gsub(/"|%/, "&&") - msg = substr($0, index($0, "|")) - sub(/^[^ \t]+[ \t]+/, "", msg) - printf "info -anchor %d.%d \"%s\"\n", line, column, msg - }' } } define-command -hidden lint-show-counters %{ - echo -markup linting results:{red} %opt{lint_error_count} error(s){yellow} %opt{lint_warning_count} warning(s) + echo -markup "linting results: {Error} %opt{lint_error_count} error(s) {Information} %opt{lint_warning_count} warning(s) " } define-command lint-enable -docstring "Activate automatic diagnostics of the code" %{ @@ -121,54 +347,82 @@ define-command lint-disable -docstring "Disable automatic diagnostics of the cod remove-hooks window lint-diagnostics } -define-command lint-next-error -docstring "Jump to the next line that contains an error" %{ - update-option buffer lint_errors +# FIXME: Is there some way we can re-use make-next-error +# instead of re-implementing it? +define-command \ + -docstring "Jump to the next line that contains a lint message" \ + lint-next-message \ +%{ + update-option buffer lint_messages evaluate-commands %sh{ - eval "set -- ${kak_quoted_opt_lint_errors}" + eval "set -- ${kak_quoted_opt_lint_messages}" shift - for i in "$@"; do - candidate="${i%%|*}" - if [ "${candidate%%.*}" -gt "${kak_cursor_line}" ]; then - range="${candidate}" + if [ "$#" -eq 0 ]; then + printf 'fail no lint messages' + exit + fi + + for lint_message; do + lineno="${lint_message%%|*}" + msg="${lint_message##*|}" + + if [ "$lineno" -gt "$kak_cursor_line" ]; then + printf "execute-keys %dg\n" "$lineno" + printf "info -anchor %d.%d %s\n" \ + "$lineno" "1" "$(kakquote "$msg")" break fi done - range="${range-${1%%|*}}" - if [ -n "${range}" ]; then - printf 'select %s\n' "${range}" - else - echo 'fail no lint diagnostics' - fi + # FIXME: should we wrap around like make-next-error? } } -define-command lint-previous-error -docstring "Jump to the previous line that contains an error" %{ - update-option buffer lint_errors +# lint-next-message was previously known as lint-next-error, +# but it includes warnings too, not just errors. +alias global lint-next-error lint-next-message + +# FIXME: Is there some way we can re-use make-previous-error +# instead of re-implementing it? +define-command \ + -docstring "Jump to the previous line that contains a lint message" \ + lint-previous-message \ +%{ + update-option buffer lint_messages evaluate-commands %sh{ - eval "set -- ${kak_quoted_opt_lint_errors}" + eval "set -- ${kak_quoted_opt_lint_messages}" shift - for i in "$@"; do - candidate="${i%%|*}" + if [ "$#" -eq 0 ]; then + printf 'fail no lint messages' + exit + fi - if [ "${candidate%%.*}" -ge "${kak_cursor_line}" ]; then - range="${last_candidate}" + last_lineno="$kak_cursor_line" + last_msg="no previous message" + + for lint_message; do + lineno="${lint_message%%|*}" + msg="${lint_message##*|}" + + if [ "$lineno" -ge "${kak_cursor_line}" ]; then + printf "execute-keys %dg\n" "$last_lineno" + printf "info -anchor %d.%d %s\n" \ + "$lineno" "1" "$(kakquote "$last_msg")" break fi - last_candidate="${candidate}" + last_lineno="$last_lineno" + last_msg="$msg" done - if [ $# -ge 1 ]; then - shift $(($# - 1)) - range="${range:-${1%%|*}}" - printf 'select %s\n' "${range}" - else - echo 'fail no lint diagnostics' - fi + # FIXME: should we wrap around like make-previous-error? } } + +# lint-previous-message was previously known as lint-previous-error, +# but it includes warnings too, not just errors. +alias global lint-previous-error lint-previous-message From 673d0818239da9b3add1a6ecad0b025e881c09e6 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 9 Feb 2020 13:23:58 +1100 Subject: [PATCH 2/8] rc lint: Address code-review comments. --- rc/tools/lint.kak | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/rc/tools/lint.kak b/rc/tools/lint.kak index 63fca562..ba6ea012 100644 --- a/rc/tools/lint.kak +++ b/rc/tools/lint.kak @@ -115,8 +115,9 @@ define-command \ done # Load all the linter messages into Kakoune options. - # Yes, shellcheck, we do want line-continuation backslashes - # inside the string. + # shellcheck warns us that the shell doesn't need + # backslash-continuation chars in a single-quoted string, + # but awk still needs them. # shellcheck disable=SC1004 awk -v file="$kak_buffile" -v client="$kak_client" ' function kakquote(text) { @@ -160,10 +161,9 @@ define-command \ # so that information is not lost. msg = msg "(col " $3 ")" - # FIXME: I *think* this line is left over from a time - # when Kakoune used pipes to delimit items in a list - # option. If so, it is entirely useless now... but I - # am not 100% sure. + # Messages will be stored in a line-specs option, + # and each record in the option uses "|" + # as a field delimiter, so we need to escape them. gsub(/\|/, "\\|", msg) if ($2 in messages_by_line) { @@ -282,7 +282,7 @@ define-command \ lintcmd="$kak_opt_lintcmd" fi - printf '%s\n' "lint-cleaned-selections $(kakquote "$lintcmd")" + printf 'lint-cleaned-selections %s\n' "$(kakquote "$lintcmd")" } } } @@ -380,10 +380,6 @@ define-command \ } } -# lint-next-message was previously known as lint-next-error, -# but it includes warnings too, not just errors. -alias global lint-next-error lint-next-message - # FIXME: Is there some way we can re-use make-previous-error # instead of re-implementing it? define-command \ @@ -422,7 +418,3 @@ define-command \ # FIXME: should we wrap around like make-previous-error? } } - -# lint-previous-message was previously known as lint-previous-error, -# but it includes warnings too, not just errors. -alias global lint-previous-error lint-previous-message From 09f067d58552094d53c8a68a151cf8f08fad75dd Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 9 Feb 2020 14:01:35 +1100 Subject: [PATCH 3/8] rc lint: More code-review comments. Don't ask Kakoune to quote values we know can never contain shell-sensitive characters, and flatten the kakquote() function to a single line for ease of copy/pasting. --- rc/tools/lint.kak | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/rc/tools/lint.kak b/rc/tools/lint.kak index ba6ea012..c23e41dd 100644 --- a/rc/tools/lint.kak +++ b/rc/tools/lint.kak @@ -37,11 +37,7 @@ define-command \ # Create a temporary directory to keep all our state. evaluate-commands %sh{ # This is going to come in handy later. - kakquote() { - printf "'" - printf "%s" "$*" | sed "s/'/''/g" - printf "'" - } + kakquote() { printf "%s" "$*" | sed "s/'/''/g; 1s/^/'/; \$s/\$/'/"; } # Before we clobber our arguments, # let's record the lintcmd we were given. @@ -65,7 +61,7 @@ define-command \ }" # Write all the selection descriptions to files. - eval set -- "$kak_quoted_selections_desc" + eval set -- "$kak_selections_desc" i=0 for desc; do mkdir -p "$dir"/sel-"$i" @@ -260,11 +256,7 @@ define-command \ evaluate-commands %sh{ # This is going to come in handy later. - kakquote() { - printf "'" - printf "%s" "$*" | sed "s/'/''/g" - printf "'" - } + kakquote() { printf "%s" "$*" | sed "s/'/''/g; 1s/^/'/; \$s/\$/'/"; } if [ "$1" = "-command" ]; then if [ -z "$2" ]; then @@ -307,11 +299,7 @@ define-command -hidden lint-show %{ update-option buffer lint_messages evaluate-commands %sh{ # This is going to come in handy later. - kakquote() { - printf "'" - printf "%s" "$*" | sed "s/'/''/g" - printf "'" - } + kakquote() { printf "%s" "$*" | sed "s/'/''/g; 1s/^/'/; \$s/\$/'/"; } eval set -- "${kak_quoted_opt_lint_messages}" shift # skip the timestamp From c1e9f46301a214f8471eed60cf25a8b94631a939 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 13 Feb 2020 20:17:01 +1100 Subject: [PATCH 4/8] rc lint: Don't start a comment with "shellcheck". That confuses shellcheck into expecting a warning pragma. --- rc/tools/lint.kak | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rc/tools/lint.kak b/rc/tools/lint.kak index c23e41dd..5f36f968 100644 --- a/rc/tools/lint.kak +++ b/rc/tools/lint.kak @@ -111,8 +111,8 @@ define-command \ done # Load all the linter messages into Kakoune options. - # shellcheck warns us that the shell doesn't need - # backslash-continuation chars in a single-quoted string, + # Inside this block, shellcheck warns us that the shell doesn't + # need backslash-continuation chars in a single-quoted string, # but awk still needs them. # shellcheck disable=SC1004 awk -v file="$kak_buffile" -v client="$kak_client" ' From cad0572ca52f0ac206b574b5445ddbcdcc25742f Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 13 Feb 2020 20:18:12 +1100 Subject: [PATCH 5/8] rc lint: Re-add missing kakquote functions. --- rc/tools/lint.kak | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rc/tools/lint.kak b/rc/tools/lint.kak index 5f36f968..91404336 100644 --- a/rc/tools/lint.kak +++ b/rc/tools/lint.kak @@ -344,6 +344,9 @@ define-command \ update-option buffer lint_messages evaluate-commands %sh{ + # This is going to come in handy later. + kakquote() { printf "%s" "$*" | sed "s/'/''/g; 1s/^/'/; \$s/\$/'/"; } + eval "set -- ${kak_quoted_opt_lint_messages}" shift @@ -377,6 +380,9 @@ define-command \ update-option buffer lint_messages evaluate-commands %sh{ + # This is going to come in handy later. + kakquote() { printf "%s" "$*" | sed "s/'/''/g; 1s/^/'/; \$s/\$/'/"; } + eval "set -- ${kak_quoted_opt_lint_messages}" shift From 48bd7387bbe903b2aaf97a994255cd2da23d8643 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 13 Feb 2020 20:19:03 +1100 Subject: [PATCH 6/8] rc lint: When parsing lint messages, use "remove shortest prefix" pattern. There might legitimately be "|" characters in the message, so we want to stop at the first one, the one that delimits the message location from the message text. --- rc/tools/lint.kak | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rc/tools/lint.kak b/rc/tools/lint.kak index 91404336..d24633bb 100644 --- a/rc/tools/lint.kak +++ b/rc/tools/lint.kak @@ -357,7 +357,7 @@ define-command \ for lint_message; do lineno="${lint_message%%|*}" - msg="${lint_message##*|}" + msg="${lint_message#*|}" if [ "$lineno" -gt "$kak_cursor_line" ]; then printf "execute-keys %dg\n" "$lineno" @@ -396,7 +396,7 @@ define-command \ for lint_message; do lineno="${lint_message%%|*}" - msg="${lint_message##*|}" + msg="${lint_message#*|}" if [ "$lineno" -ge "${kak_cursor_line}" ]; then printf "execute-keys %dg\n" "$last_lineno" From 59e273c316893863b5c3e6c43dbc22e5a89c4e1a Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 13 Feb 2020 20:26:08 +1100 Subject: [PATCH 7/8] rc lint: Teach lint-{next,previous}-message to wrap around the buffer. This matches the behaviour of make-{next,previous}-error. --- rc/tools/lint.kak | 59 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/rc/tools/lint.kak b/rc/tools/lint.kak index d24633bb..d0632962 100644 --- a/rc/tools/lint.kak +++ b/rc/tools/lint.kak @@ -355,19 +355,34 @@ define-command \ exit fi + first_lineno="" + first_msg="" + for lint_message; do lineno="${lint_message%%|*}" msg="${lint_message#*|}" + if [ -z "$first_lineno" ]; then + first_lineno=$lineno + first_msg=$msg + fi + if [ "$lineno" -gt "$kak_cursor_line" ]; then printf "execute-keys %dg\n" "$lineno" printf "info -anchor %d.%d %s\n" \ "$lineno" "1" "$(kakquote "$msg")" - break + exit fi done - # FIXME: should we wrap around like make-next-error? + # We didn't find any messages after the current line, + # let's wrap around to the beginning. + printf "execute-keys %dg\n" "$first_lineno" + printf "info -anchor %d.%d %s\n" \ + "$first_lineno" "1" "$(kakquote "$first_msg")" + printf "echo -markup \ + {Information}lint message search wrapped around buffer\n" + } } @@ -391,24 +406,46 @@ define-command \ exit fi - last_lineno="$kak_cursor_line" - last_msg="no previous message" + prev_lineno="" + prev_msg="" for lint_message; do lineno="${lint_message%%|*}" msg="${lint_message#*|}" + # If this message comes on or after the cursor position... if [ "$lineno" -ge "${kak_cursor_line}" ]; then - printf "execute-keys %dg\n" "$last_lineno" - printf "info -anchor %d.%d %s\n" \ - "$lineno" "1" "$(kakquote "$last_msg")" - break + # ...and we had a previous message... + if [ -n "$prev_lineno" ]; then + # ...then go to the previous message and display it. + printf "execute-keys %dg\n" "$prev_lineno" + printf "info -anchor %d.%d %s\n" \ + "$lineno" "1" "$(kakquote "$prev_msg")" + exit + + # We are after the cursor position, but there has been + # no previous message; we'll need to do something else. + else + break + fi fi - last_lineno="$last_lineno" - last_msg="$msg" + # We have not yet reached the cursor position, stash this message + # and try the next. + prev_lineno="$lineno" + prev_msg="$msg" done - # FIXME: should we wrap around like make-previous-error? + # There is no message before the cursor position, + # let's wrap around to the end. + shift $(( $# - 1 )) + last_lineno="${1%%|*}" + last_msg="${1#*|}" + + printf "execute-keys %dg\n" "$last_lineno" + printf "info -anchor %d.%d %s\n" \ + "$last_lineno" "1" "$(kakquote "$last_msg")" + printf "echo -markup \ + {Information}lint message search wrapped around buffer\n" } } From 92771216954f6522772d6d03c6438e89a51dd301 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Fri, 14 Feb 2020 17:27:36 +1100 Subject: [PATCH 8/8] rc lint: Change flag symbols for lint errors and warnings. As suggested in code review. --- rc/tools/lint.kak | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rc/tools/lint.kak b/rc/tools/lint.kak index d0632962..3774c365 100644 --- a/rc/tools/lint.kak +++ b/rc/tools/lint.kak @@ -133,7 +133,7 @@ define-command \ # Remember that an error or a warning occurs on this line.. if ($4 ~ /[Ee]rror/) { # We definitely have an error on this line. - flags_by_line[$2] = "{Error}!" + flags_by_line[$2] = "{Error}x" error_count++ } else if (flags_by_line[$2] ~ /Error/) { # We have a warning on this line, @@ -142,7 +142,7 @@ define-command \ } else { # We have a warning on this line, # and no previous error. - flags_by_line[$2] = "{Information}?" + flags_by_line[$2] = "{Information}!" warning_count++ }