Skip to content
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

> replace powerful or confusing? #3279

Closed
Gavin-Holt opened this issue May 1, 2024 · 2 comments
Closed

> replace powerful or confusing? #3279

Gavin-Holt opened this issue May 1, 2024 · 2 comments

Comments

@Gavin-Holt
Copy link

Gavin-Holt commented May 1, 2024

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: 68d88b5
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:

  • '-a' Replace all occurrences at once
  • '-l' Do a literal search instead of a regex search

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.

  • You can prevent shell parsing by using single quotes.
  • You can prevent regex parsing with -l (literal) flag.

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:

  • backslash \
  • caret ^
  • dollar sign $
  • period or dot .
  • pipe symbol |
  • question mark ?
  • asterisk *
  • plus +
  • parenthesis ()
  • opening square bracket [
  • opening curly brace {

Escape metacharacters with \ except for $ which is different.

  • '$$foo' would give the string $foo
  • '\$' gives the $ character

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:

  • '$foo' would give the capture group named foo
    e.g.
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:

  • \ Escapes the following character
  • $ Looks for an environment variable
  • \\$ Returns the $ character
  • Others???

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
Copy link

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
Copy link
Author

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants