Skip to content

Commit

Permalink
fix: Unescaping certain regex options.
Browse files Browse the repository at this point in the history
Many regexes contain escaped characters
like `\s` or `\w`.
`tmux-fastcopy` queries the tmux environment
for regex overwrites.
Specifically,
it uses the `tmux show-options -g` command.
The output in turn escapes the backward slashes,
turning `\s` into `\\s`.
To correctly parse the regex overwrites,
`tmux-fastcopy` needs to unescape these backward slashes too.

The `tmux show-options -g` command prints values in three forms:

-   Unquoted for simple, unspaced values:

    ```shell
    $ tmux set @myopt hey ; tmux show @myopt
    @myopt hey
    ```

-   Single-quoted for simple, double-quoted values:

    ```shell
    $ tmux set @myopt hey\"world ; tmux show @myopt
    @myopt 'hey"world'
    ```

-   Double-quoted for other values:

    ```shell
    $ tmux set @myopt hey\  ; tmux show @myopt
    @myopt "hey "
    ```

Note that the output escapes backward slashes
in all three forms:

```shell
$ tmux set @myopt '\hey' ; tmux show @myopt
@myopt \\hey

$ tmux set @myopt '\"hey' ; tmux show @myopt
@myopt '\\"hey'

$ tmux set @myopt '\ hey' ; tmux show @myopt
@myopt "\\ hey"
```

For many regexes,
tmux would print the value unquoted.
For example, the path regex built-in to `tmux-fastcopy` is like this:

```shell
$ tmux set-option @myopt '(\b([\w.-]+|~)?(/[\w.-]+)+\b)' ; tmux show @myopt
@myopt (\\b([\\w.-]+|~)?(/[\\w.-]+)+\\b)
```

Currently,
`tmux-fastcopy` relies on `strconv.Unquote`
in the `tmuxopt.Loader.ReadValue` function
to unescape the backslashes.
However,
a caveat is that `strconv.Unquote` only performs
if the given string is quoted.
As a result,
`tmux-fastcopy` never unescapes the regex from the last paragraph,
and would fail to match it.

This commit fixes the problem
by manually double-quoting unquoted strings,
forcing `strconv.Unquote` to unescape them.
  • Loading branch information
Jy Yuan committed Dec 3, 2023
1 parent 5dbed5a commit dbc288a
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 8 deletions.
24 changes: 16 additions & 8 deletions internal/tmux/tmuxopt/tmuxopt.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,21 +171,29 @@ func readValue(v []byte) (value string) {
}

value = string(v)
// Try to unquote but don't fail if it doesn't work.
switch value[0] {
case '\'':
if strings.HasPrefix(value, `'`) {
// strconv.Unquote does not like single-quoted strings with
// multiple characters. Invert the quotes to let
// strconv.Unquote do the heavy-lifting and invert back.
value = invertQuotes(value)
defer func() {
value = invertQuotes(value)
}()
fallthrough
case '"':
if o, err := strconv.Unquote(value); err == nil {
value = o
}
} else if !strings.Contains(value, `"`) {
// If a string is unquoted,
// manually quote it to get the benefit of un-escaping characters
// from `strconv.Unquote`.
// This does not cover the case
// where `value` has a double-quote anywhere in the string.
// However,
// since `value` comes from `tmux show-options`,
// values containing double-quotes
// come in single-quotes.
value = `"` + value + `"`
}
// Try to unquote but don't fail if it doesn't work.
if o, err := strconv.Unquote(value); err == nil {
value = o
}
return value
}
Expand Down
10 changes: 10 additions & 0 deletions internal/tmux/tmuxopt/tmuxopt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ func TestLoaderStrings(t *testing.T) {
options: []string{"foo"},
want: []string{`foo \" bar`},
},
{
desc: "unquote/escape/unquoted",
give: unlines(
`foo foo\\sbar`,
// == set-option -g foo 'foo\sbar'
// == set-option -g foo "foo\\sbar"
),
options: []string{"foo"},
want: []string{`foo\sbar`},
},
{
// For
// https://github.com/abhinav/tmux-fastcopy/issues/48.
Expand Down

0 comments on commit dbc288a

Please sign in to comment.