-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Fix function definition highlighting #563
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
It's so easy now that we have the array that I wonder why we didn't do it before.
Some minor suggestions and a whole list of test cases for your enjoyment. :)
# - :regular: "Not a command word", and command delimiters are permitted. | ||
# Mainly used to detect premature termination of commands. | ||
# - :always: The word 'always' in the «{ foo } always { bar }» syntax. | ||
# - :function: Function names after function or before () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quote the reserved words function
and ()
for clarity.
# try-always construct | ||
style=reserved-word # de facto a reserved word, although not de jure | ||
next_word=':start:' | ||
elif [[ $this_word == :function: ]]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most state checks use asterisks before/after the colon. Shouldn't this do the same? (I suspect it should, but even if not it definitely deserves a comment explaining the exception.)
* `dollar-double-quoted-argument` - parameter expansion inside double quotes (`$foo` inside `""`) | ||
* `back-double-quoted-argument` - backslash escape sequences inside double-quoted arguments (`\"` in `"foo\"bar"`) | ||
* `back-dollar-quoted-argument` - backslash escape sequences inside dollar-quoted arguments (`\x` in `$'\x48'`) | ||
* `function-definition` - function name(s) when defining a function (`f` and `g` in `f g () { : }`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test cases (written before I read the diff):
function { pwd }
— anonymous function
function pwd
— defines a function named pwd
, not runs that command
function >/dev/null { pwd }
— anonymous function
function f >/dev/null { pwd }
— named function with sticky redirection
function >/dev/null f { pwd }
— syntax error (!)
The above also support an optional ()
after the function names and before the brace.
() {}
— anonymous function
() pwd
— anonymous function
() () () pwd
— anonymous function for calling tor
The above also come in named variants.
function () () pwd
— two anonymous functions
function f () () pwd
— named function whose body is an anonymous function
function () f () pwd
— anonymous function that defines a function named f
function () () f pwd
— two anonymous functions, f
is in command position (unknown-token)
Then there's the MULTI_FUNC_DEF variants of all these.
Then there's
unsetopt multifuncdef; function f g h { pwd }
— creates a function named f
. Probably a zsh bug, actually, but shouldn't we highlight g
and h
as errors nevertheless? (I saw the test for the non-function
-syntax variant of this.)
Question: In () pwd
, should the ()
be highlighted as a command position? What about function { pwd }
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another case (github didn't let me edit comment after I pressed the green button):
% function f
pwd
% f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fun fact: function >/dev/null f { pwd }
is only a syntax error when right_brace_is_recognised_everywhere
is true. The redirection makes it an anonymous function that executes f
. The wonders of zsh's grammar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should the newline be highlighted as?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about highlighting it the same way as the newlines in
for 1 in foo bar baz
do
echo $1
done
?
this_word=':start::regular:' | ||
;; | ||
('function') | ||
next_word=:function: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: I usually quote ':foo:'
tokens, partly for Vim syntax highlighting purposes. We should probably be consistent one way or the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I was wondering why many were quoted. I'll match.
fi | ||
'()') | ||
# Function definition was handled above | ||
style=unknown-token |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When can this happen? f g ()
with nomultifuncdef, function "foo'bar" ()
, …?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or after a redirection or in an array assignment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about empty case
patterns? case foo in (bar) ;; esac
→ case foo in () ;; esac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now it's highlighted as reserved-word
which isn't correct either. We'll probably need another state to handle case correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this branch the ()
in case
is highlighted as unknown-token — which is correct, since it's a syntax error. Let's discuss case
on #406.
if (( ${+precommand_options[$arg]} )) && _zsh_highlight_main__is_runnable $arg; then | ||
if [[ $res != reserved && ( $args[1] == '()' || | ||
# TODO: Function names can be absurd; this handles the more common cases without invoking Cthulhu. | ||
( $zsyh_user_options[multifuncdef] == on && $args[(r)*[^[:alnum:]_-]*] == '()' ) ) ]]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we could do something along the line of "after function
, everything that isn't a token (&&
, >
, etc) or the reserved words {
or ()
is a function name? Haven't looked at Src/parse.c of this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function
already has that in effect. This branch only effects words before ()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, that's what I meant. "If one of the following words is ()
, and it's in the same simple command as the current word, then all intervening words [other than redirections] are function names" or something like this. Basically, we know that "everything from the start of the command to the ()
token is function names", with some exceptions (noglob
, redirections, …), so I wonder if a blacklist might be better than a whitelist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would probably be a better approach, but I'm not sure how to keep it fast or how to enumerate all of the invalid function names.
(Aside noglob () pwd
is a valid function definition.)
4433121
to
c2114f1
Compare
c2114f1
to
35d7f8c
Compare
35d7f8c
to
cd64662
Compare
cd64662
to
64b13f5
Compare
@phy1729 This is milestoned 0.8.0. Do you intend to work on it for the 0.8.0 release? If yes, great; if not, could you re-milestone it appropriately? Cheers. If it's waiting on me, let me know! |
(Assigning until the question is answered. Feel free to unassign yourself if needed.) |
Triage: Bumping to the next milestone due to feedback timeout. |
Fixes #223
Adds new
function-definition
style; thoughts on what that should be by default?