Skip to content

Commit 889bdfa

Browse files
committed
main: Add arithmetic substitution highlighting
Closes zsh-users#607 zsh-users#649 zsh-users#704
1 parent ea3ae74 commit 889bdfa

File tree

6 files changed

+122
-27
lines changed

6 files changed

+122
-27
lines changed

changelog.md

+3-7
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,6 @@
4444
- Fix `echo >&p` highlighting the `p` as a filename if a file by that name happened to exist
4545
[part of #645]
4646

47-
- Fix `: $((42))` being highlighted as a subshell.
48-
[part of #607]
49-
50-
- Regress highlighting of `: $((ls); (ls))`: is a subshell, but will now be
51-
incorrectly highlighted as an arithmetic expansion.
52-
[#704]
53-
5447
- Fix wrong highlighting of unquoted parameter expansions under zsh 5.2 and older
5548
[e165f18c758e]
5649

@@ -79,6 +72,9 @@
7972
`_zsh_highlight_main__precmd_hook:1: array parameter _zsh_highlight_main__command_type_cache set in enclosing scope in function _zsh_highlight_main__precmd_hook`
8073
[#727, #731, #732, #733]
8174

75+
- Highlight arithmetic expansions (e.g., `$(( 42 ))`)
76+
[#607 #649 #704]
77+
8278
# Changes in version 0.7.1
8379

8480
- Remove out-of-date information from the 0.7.0 changelog.

docs/highlighters/main.md

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ This highlighter defines the following styles:
4242
* `command-substitution-delimiter-quoted` - a quoted command substitution delimiters (`"$(` and `)"`)
4343
* `process-substitution` - process substitutions (`<(echo foo)`)
4444
* `process-substitution-delimiter` - process substitution delimiters (`<(` and `)`)
45+
* `arithmetic-expansion` - arithmetic expansion `$(( 42 ))`)
4546
* `single-hyphen-option` - single-hyphen options (`-o`)
4647
* `double-hyphen-option` - double-hyphen options (`--option`)
4748
* `back-quoted-argument` - backtick command substitution (`` `foo` ``)

highlighters/main/main-highlighter.zsh

+106-9
Original file line numberDiff line numberDiff line change
@@ -1338,8 +1338,13 @@ _zsh_highlight_main_highlighter_highlight_argument()
13381338
(( i = REPLY ))
13391339
highlights+=($reply)
13401340
continue
1341-
elif [[ $arg[i+1] == $'\x28' && ${arg:$i} != $'\x28\x28'*$'\x29\x29'* ]]; then
1342-
# command substitution that doesn't look like an arithmetic expansion
1341+
elif [[ $arg[i+1] == $'\x28' ]]; then
1342+
if [[ $arg[i+2] == $'\x28' ]] && _zsh_highlight_main_highlighter_highlight_arithmetic $i; then
1343+
# Arithmetic expansion
1344+
(( i = REPLY ))
1345+
highlights+=($reply)
1346+
continue
1347+
fi
13431348
start=$i
13441349
(( i += 2 ))
13451350
_zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,-1]
@@ -1354,10 +1359,6 @@ _zsh_highlight_main_highlighter_highlight_argument()
13541359
highlights+=($(( start_pos + i - 1)) $(( start_pos + i )) command-substitution-delimiter-unquoted)
13551360
fi
13561361
continue
1357-
else
1358-
# TODO: if it's an arithmetic expansion, skip past it, to prevent
1359-
# multiplications from being highlighted as globbing (issue #607,
1360-
# test-data/arith1.zsh)
13611362
fi
13621363
while [[ $arg[i+1] == [=~#+'^'] ]]; do
13631364
(( i += 1 ))
@@ -1485,11 +1486,17 @@ _zsh_highlight_main_highlighter_highlight_double_quote()
14851486
# $#, $*, $@, $?, $- - like $$ above
14861487
(( k += 1 )) # highlight both dollar signs
14871488
(( i += 1 )) # don't consider the second one as introducing another parameter expansion
1488-
elif [[ $arg[i+1] == $'\x28' && ${arg:$i} != $'\x28\x28'*$'\x29\x29'* ]]; then
1489-
# command substitution that doesn't look like an arithmetic expansion
1489+
elif [[ $arg[i+1] == $'\x28' ]]; then
1490+
saved_reply=($reply)
1491+
if [[ $arg[i+2] == $'\x28' ]] && _zsh_highlight_main_highlighter_highlight_arithmetic $i; then
1492+
# Arithmetic expansion
1493+
(( i = REPLY ))
1494+
reply=($saved_reply $reply)
1495+
continue
1496+
fi
1497+
14901498
breaks+=( $last_break $(( start_pos + i - 1 )) )
14911499
(( i += 2 ))
1492-
saved_reply=($reply)
14931500
_zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,-1]
14941501
ret=$?
14951502
(( i += REPLY ))
@@ -1670,6 +1677,96 @@ _zsh_highlight_main_highlighter_highlight_backtick()
16701677
REPLY=$i
16711678
}
16721679

1680+
# Highlight special chars inside arithmetic expansions
1681+
_zsh_highlight_main_highlighter_highlight_arithmetic()
1682+
{
1683+
local -a saved_reply
1684+
local style
1685+
integer i j k paren_depth ret
1686+
reply=()
1687+
1688+
for (( i = $1 + 3 ; i <= end_pos - start_pos ; i += 1 )) ; do
1689+
(( j = i + start_pos - 1 ))
1690+
(( k = j + 1 ))
1691+
case "$arg[$i]" in
1692+
[\'\"\\@{}])
1693+
style=unknown-token
1694+
;;
1695+
'(')
1696+
(( paren_depth++ ))
1697+
continue
1698+
;;
1699+
')')
1700+
if (( paren_depth )); then
1701+
(( paren_depth-- ))
1702+
continue
1703+
fi
1704+
[[ $arg[i+1] == ')' ]] && { (( i++ )); break; }
1705+
# Special case ) at the end of the buffer to avoid flashing command substitution for a character
1706+
(( has_end && (len == k) )) && break
1707+
# This is a single paren and there are no open parens, so this isn't an arithmetic expansion
1708+
return 1
1709+
;;
1710+
'`')
1711+
saved_reply=($reply)
1712+
_zsh_highlight_main_highlighter_highlight_backtick $i
1713+
(( i = REPLY ))
1714+
reply=($saved_reply $reply)
1715+
continue
1716+
;;
1717+
'$' )
1718+
if [[ $arg[i+1] == $'\x28' ]]; then
1719+
saved_reply=($reply)
1720+
if [[ $arg[i+2] == $'\x28' ]] && _zsh_highlight_main_highlighter_highlight_arithmetic $i; then
1721+
# Arithmetic expansion
1722+
(( i = REPLY ))
1723+
reply=($saved_reply $reply)
1724+
continue
1725+
fi
1726+
1727+
(( i += 2 ))
1728+
_zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,end_pos]
1729+
ret=$?
1730+
(( i += REPLY ))
1731+
reply=(
1732+
$saved_reply
1733+
$j $(( start_pos + i )) command-substitution-quoted
1734+
$j $(( j + 2 )) command-substitution-delimiter-quoted
1735+
$reply
1736+
)
1737+
if (( ret == 0 )); then
1738+
reply+=($(( start_pos + i - 1 )) $(( start_pos + i )) command-substitution-delimiter)
1739+
fi
1740+
continue
1741+
else
1742+
continue
1743+
fi
1744+
;;
1745+
($histchars[1]) # ! - may be a history expansion
1746+
if [[ $arg[i+1] != ('='|$'\x28'|$'\x7b'|[[:blank:]]) ]]; then
1747+
style=history-expansion
1748+
else
1749+
continue
1750+
fi
1751+
;;
1752+
*)
1753+
continue
1754+
;;
1755+
1756+
esac
1757+
reply+=($j $k $style)
1758+
done
1759+
1760+
if [[ $arg[i] != ')' ]]; then
1761+
# If unclosed, i points past the end
1762+
(( i-- ))
1763+
fi
1764+
style=arithmetic-expansion
1765+
reply=($(( start_pos + $1 - 1)) $(( start_pos + i )) arithmetic-expansion $reply)
1766+
REPLY=$i
1767+
}
1768+
1769+
16731770
# Called with a single positional argument.
16741771
# Perform filename expansion (tilde expansion) on the argument and set $REPLY to the expanded value.
16751772
#

highlighters/main/test-data/arith-cmdsubst-mess.zsh

+10-10
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ BUFFER=$': $((ls); (ls))'
3333
expected_region_highlight=(
3434
'1 1 builtin' # :
3535
'3 15 default' # $((ls); (ls))
36-
'3 15 command-substitution-unquoted "issue #704"' # $((ls); (ls))
37-
'3 4 command-substitution-delimiter-unquoted "issue #704"' # $(
38-
'5 5 reserved-word "issue #704"' # (
39-
'6 7 command "issue #704"' # ls
40-
'8 8 reserved-word "issue #704"' # )
41-
'9 9 commandseparator "issue #704"' # ;
42-
'11 11 reserved-word "issue #704"' # (
43-
'12 13 command "issue #704"' # ls
44-
'14 14 reserved-word "issue #704"' # )
45-
'15 15 command-substitution-delimiter-unquoted "issue #704"' # )
36+
'3 15 command-substitution-unquoted' # $((ls); (ls))
37+
'3 4 command-substitution-delimiter-unquoted' # $(
38+
'5 5 reserved-word' # (
39+
'6 7 command' # ls
40+
'8 8 reserved-word' # )
41+
'9 9 commandseparator' # ;
42+
'11 11 reserved-word' # (
43+
'12 13 command' # ls
44+
'14 14 reserved-word' # )
45+
'15 15 command-substitution-delimiter-unquoted' # )
4646
)

highlighters/main/test-data/arith1.zsh

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ BUFFER=$': $(( 6 * 9 ))'
3333
expected_region_highlight=(
3434
'1 1 builtin' # :
3535
'3 14 default' # $(( 6 * 9 ))
36+
'3 14 arithmetic-expansion' # $(( 6 * 9 ))
3637
)
37-
expected_mismatch="currently the actual highlighting has one superfluous group that highlights the asterisk is highlighted as 'globbing'"

highlighters/main/test-data/arith2.zsh

+1
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ expected_region_highlight=(
3434
'1 1 builtin' # :
3535
'3 16 default' # "$(( 6 * 9 ))"
3636
'3 16 double-quoted-argument' # "$(( 6 * 9 ))"
37+
'4 15 arithmetic-expansion' # $(( 6 * 9 ))
3738
)

0 commit comments

Comments
 (0)