Skip to content

Commit a238647

Browse files
committed
main: Add arithmetic substitution highlighting
Closes #607 #649 #704
1 parent f8b1470 commit a238647

File tree

6 files changed

+121
-27
lines changed

6 files changed

+121
-27
lines changed

changelog.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,6 @@
5050
- Fix `echo >&p` highlighting the `p` as a filename if a file by that name happened to exist
5151
[part of #645]
5252

53-
- Fix `: $((42))` being highlighted as a subshell.
54-
[part of #607]
55-
56-
- Regress highlighting of `: $((ls); (ls))`: is a subshell, but will now be
57-
incorrectly highlighted as an arithmetic expansion.
58-
[#704]
59-
6053
- Fix wrong highlighting of unquoted parameter expansions under zsh 5.2 and older
6154
[e165f18c758e]
6255

@@ -89,6 +82,8 @@
8982
(such as `;`, `|`, `&&`) before a newline
9083
[#677; had regressed in 0.7.0]
9184

85+
- Highlight arithmetic expansions (e.g., `$(( 42 ))`)
86+
[#607 #649 #704]
9287

9388
# Changes in version 0.7.1
9489

docs/highlighters/main.md

Lines changed: 1 addition & 0 deletions
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

Lines changed: 106 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,8 +1350,13 @@ _zsh_highlight_main_highlighter_highlight_argument()
13501350
(( i = REPLY ))
13511351
highlights+=($reply)
13521352
continue
1353-
elif [[ $arg[i+1] == $'\x28' && ${arg:$i} != $'\x28\x28'*$'\x29\x29'* ]]; then
1354-
# command substitution that doesn't look like an arithmetic expansion
1353+
elif [[ $arg[i+1] == $'\x28' ]]; then
1354+
if [[ $arg[i+2] == $'\x28' ]] && _zsh_highlight_main_highlighter_highlight_arithmetic $i; then
1355+
# Arithmetic expansion
1356+
(( i = REPLY ))
1357+
highlights+=($reply)
1358+
continue
1359+
fi
13551360
start=$i
13561361
(( i += 2 ))
13571362
_zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,-1]
@@ -1366,10 +1371,6 @@ _zsh_highlight_main_highlighter_highlight_argument()
13661371
highlights+=($(( start_pos + i - 1)) $(( start_pos + i )) command-substitution-delimiter-unquoted)
13671372
fi
13681373
continue
1369-
else
1370-
# TODO: if it's an arithmetic expansion, skip past it, to prevent
1371-
# multiplications from being highlighted as globbing (issue #607,
1372-
# test-data/arith1.zsh)
13731374
fi
13741375
while [[ $arg[i+1] == [=~#+'^'] ]]; do
13751376
(( i += 1 ))
@@ -1497,11 +1498,17 @@ _zsh_highlight_main_highlighter_highlight_double_quote()
14971498
# $#, $*, $@, $?, $- - like $$ above
14981499
(( k += 1 )) # highlight both dollar signs
14991500
(( i += 1 )) # don't consider the second one as introducing another parameter expansion
1500-
elif [[ $arg[i+1] == $'\x28' && ${arg:$i} != $'\x28\x28'*$'\x29\x29'* ]]; then
1501-
# command substitution that doesn't look like an arithmetic expansion
1501+
elif [[ $arg[i+1] == $'\x28' ]]; then
1502+
saved_reply=($reply)
1503+
if [[ $arg[i+2] == $'\x28' ]] && _zsh_highlight_main_highlighter_highlight_arithmetic $i; then
1504+
# Arithmetic expansion
1505+
(( i = REPLY ))
1506+
reply=($saved_reply $reply)
1507+
continue
1508+
fi
1509+
15021510
breaks+=( $last_break $(( start_pos + i - 1 )) )
15031511
(( i += 2 ))
1504-
saved_reply=($reply)
15051512
_zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,-1]
15061513
ret=$?
15071514
(( i += REPLY ))
@@ -1682,6 +1689,96 @@ _zsh_highlight_main_highlighter_highlight_backtick()
16821689
REPLY=$i
16831690
}
16841691

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

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

Lines changed: 10 additions & 10 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 0 deletions
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)