zyedidia / micro

A modern and intuitive terminal-based text editor
https://micro-editor.github.io
MIT License
24.39k stars 1.16k forks source link

> replace powerful or confusing? #3279

Closed Gavin-Holt closed 1 month ago

Gavin-Holt commented 2 months ago

Hi

Could someone more knowledgeable than me check this help file I have made for the replace/replaceall command.

Kind Regards Gavin Holt OS: Windows 10 Version: 2.0.13 Commit hash: 68d88b57 Compiled on April 20, 2024

Replacing text in micro editor

> replace "search" "value" "flags"  
    OR
> replace 'search' 'value' 'flags'  

The flags are optional. Possible flags are:

If you make a selection, search and replace will only happen in the selected region.

Instructions to the replace command may end up being be parsed twice - once by the shell argument parser, and then by the regex parser. This causes problems with special characters.

This gives eight combinations:

> replace 'abc' 'def'
> replace "abc" 'def'
> replace "abc" "def"
> replace 'abc' "def"
> replace 'abc' 'def' -l
> replace "abc" 'def' -l
> replace "abc" "def" -l
> replace 'abc' "def" -l

Replace will search for \t ASCII escape sequence:

e.g. Expand all tabs to four spaces (the expand utility might be better)

> replace "\t" "    "

or

> replace '\t' '    '

I could not get replace to insert \t.

It appears that replace works on single lines only, so you can't find or insert \n nor \r.

Simple replacements

Strings without spaces don't need to be quoted, but replace behaves as if there are double quotes (read below)

e.g.

> replace string1 string2

e.g.

> replaceall \\$ £

Strings with spaces need to be quoted, and the type of quotes changes behavior.

Working without shell parsing (Single quotes)

The Regex parser will look for metacharacters:

Escape metacharacters with \ except for $ which is different.

e.g. Replace all $ with £

> replace '\$' '£'

e.g. Replace all \ with /

> replaceall '\\' '/' 

e.g. Replace all " with ' needs double quotes for the replacement.

> replaceall '"' "'"

Capture groups are recognised:

replace "(foo)" "$1-bar"
replace "(foo)" "${1}-bar"
replace "(?P<group>foo)" "$group-bar"
replace "(?P<group>foo)" "$group-bar"
replace "(?P<key>\w+):\s+(?P<value>\w+)$" "$key=$value"

NB. Any command ending in a \ will kill micro on Windows.

Working with shell parsing (Double quotes)

Some characters must be escaped twice to reach the underlying functions. Shell parsing does not seem to work in Windows (either with $ prefix or wrapped in %%)

The following characters are special to the shell parser:

Escape with \ or \\ depending upon what you want to pass to the replace function

e.g. Replace all $ with £

> replaceall "\\$" "£"

e.g. Replace all \ with / - requires extra \ to preserve the closing "

> replaceall "\\\\" "/"

Further examples using/escaping shell parsing need to go here

Working with the '-l' flag

The '-l' flag turns off regex parsing to allow literal replacements. However, with double quotes there is still shell parsing so some escaping is required.

Replacing control character

I use external tools instead:

-- Replace all newlines in selection
> textfilter sed.exe -z 's/\n//g'
-- Replace all tabs in selection
> textfilter sed.exe -z 's/\t/    /g'
glupi-borna commented 2 months ago

Some notes, not in any particular order:

Neither parser expands ASCII escape sequences: [...]

Replacing control character

I use external tools instead:

I just tried

> replace '\t' '    '

and it worked fine. Maybe this is specific to Windows.

However, I also tried

> replace '\n' '\n\n'

and that did not work. I investigated a bit and my best guess is that this is because the ReplaceRegex function (in search.go) works on individual lines instead of the whole buffer, and (I'm guessing, again) micro does not store the newline character in its line representation.


If the two arguments to replace can have different quoting, then the number of combinations rises to ??? 16.

This is incorrect, for reasons I explain lower. There are 8 combinations:

> replace 'abc' 'def'
> replace "abc" 'def'
> replace "abc" "def"
> replace 'abc' "def"
> replace 'abc' 'def' -l
> replace "abc" 'def' -l
> replace "abc" "def" -l
> replace 'abc' "def" -l

However, I'm not quite sure how important the number of combinations is to explaining how the commands work. Shell splitting and the regex/literal flag are orthogonal features that will naturally multiply the amount of possible combos, but I don't think it's helpful to think about them in that way.

Instead, it would be better to explain them as separate features, and then maybe give some examples of how they could interact.


'$$foo' would give the string [[$foo]]

I was staring at this for a while, confused by the [[]]. Why not just:

'$$foo' would give the string '$foo'

Same goes for

'$foo' would give the capture group named [[foo]]


Does the '-l' flag prevent shell parsing???

After a quick glance at the code, it looks like it does not. Shell splitting is performed for all commands, before micro even knows what the command is. So you actually can't prevent shell splitting, barring some new feature being added. -l just means that, after shell splitting, the search/replace will be performed with the literal arguments provided.


NB. Any command ending in a \ will kill micro in Windows.

As reported in #2666, I see. Fixing it properly would probably require either forking kballard/go-shellquote, or finding and implementing some workaround on micro's side. Either way, I think that a hard crash is not acceptable here.

Gavin-Holt commented 2 months ago

Hi

Many thanks for your contribution, I have updated the top post with credits.

I can't get shell parsing to work on Windows, any examples of using or escaping welcome.

Kind Regards Gavin Holt

PS. I have removed the [[]] this is my go-to alternate string delimiter, if I don't want to use quotes (used in DOS batch files and in Lua)