Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save romainl/047aca21e338df7ccf771f96858edb86 to your computer and use it in GitHub Desktop.
Save romainl/047aca21e338df7ccf771f96858edb86 to your computer and use it in GitHub Desktop.

Revisions

  1. romainl revised this gist Mar 20, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Vim_pushing_built-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ Searching can be an efficient way to navigate the current buffer.

    The first search commands we learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine our search pattern. `/` and `?` really shine when all we want is to jump to something we already have our eyeballs on but they are not fit for *every* situation:

    * when we want to search something that's not directly *there*, those two commands can make us loose context very quickly,
    * when we want to search something that's not directly *there*, those two commands can make us lose context very quickly,
    * when we need to compare the matches.

    ## A better way
  2. romainl revised this gist Apr 12, 2020. 1 changed file with 13 additions and 7 deletions.
    20 changes: 13 additions & 7 deletions Vim_pushing_built-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,6 @@
    # The situation
    # Vim: pushing built-in features beyond their limits

    ## The situation

    Searching can be an efficient way to navigate the current buffer.

    @@ -7,7 +9,7 @@ The first search commands we learn are usually `/` and `?`. These are seriously
    * when we want to search something that's not directly *there*, those two commands can make us loose context very quickly,
    * when we need to compare the matches.

    # A better way
    ## A better way

    A better candidate for those situations would be the awesome `:g[lobal]/pattern/command` but it uses the `:p[rint]` command by default, which is not that useful:

    @@ -35,7 +37,7 @@ This doesn't look like much but `:g/pattern/#` is an immensely useful tool that

    And will *always* do.

    # A *better* better way
    ## A *better* better way

    As is, this command requires us to type:

    @@ -47,7 +49,7 @@ As is, this command requires us to type:

    The pattern and the line number can't be known in advance, of course, but we can certainly simplify the rest.

    ## Steps 1 and 3
    ### Steps 1 and 3

    This is the easiest (and thus most boring) part. Starting with `:g/pattern/#<CR>`, it's relatively easy to come up with a simple mapping:

    @@ -59,7 +61,7 @@ that populates the command-line with a command stub and moves the cursor between

    Executing our search is now reduced to `<key>` + pattern + `<CR>`, which is not bad at all. But what about the prompt? What if we could reduce that `:` + digits + `<CR>` part?

    ## Step 4
    ### Step 4

    This problem is a bit more complex (and thus a lot more interesting) but it's very doable with a bit of straightforward vimscript:

    @@ -84,7 +86,7 @@ The idea is to automatize the `<CR>` then `:` sequence when the command we typed

    We are now down to `<key>` + pattern + `<CR>` + digits + `<CR>`. Yes, that's a "core" of only **three** motherfucking keystrokes for the whole process!

    # Generalizing
    ## Generalizing

    Sure, streamlining that boring (but mighty) `:g/foo/#<CR>:17<CR>` was quite an achievement but we undoubtedly learned a lot of similar list-like commands in the meantime: `:ls`, `:changes`, `:ilist` and so on. Creating a common mapping for all those commands is obviously out of question but… what if we could add an automatic prompt for *all of them*?

    @@ -172,4 +174,8 @@ OK, but we still have only **one** mapping for `:g//#`. What about the other com

    Sure we could go on a hunt for available keys and create mappings for just about every list-like command but that will make a lot to remember for commands we don't use that much anyway. Instead, let's consider this function and this command-line mode mapping as "enablers" that make using those list-like commands a lot easier.

    If we notice one such command creeping into our workflow, well… we will map it!
    If we notice one such command creeping into our workflow, well… we will map it!

    ---

    [My Vim-related gists](https://gist.github.com/romainl/4b9f139d2a8694612b924322de1025ce).
  3. romainl revised this gist Nov 17, 2017. No changes.
  4. romainl renamed this gist Oct 8, 2017. 1 changed file with 0 additions and 0 deletions.
  5. romainl revised this gist Jan 1, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Vim_pushing_buil-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    Searching can be an efficient way to navigate the current buffer.

    The first search commands we learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine our search pattern. But `/` and `?` really shine when all we want is to jump to something we already have our eyeballs on but they are not fit for *every* situation:
    The first search commands we learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine our search pattern. `/` and `?` really shine when all we want is to jump to something we already have our eyeballs on but they are not fit for *every* situation:

    * when we want to search something that's not directly *there*, those two commands can make us loose context very quickly,
    * when we need to compare the matches.
  6. romainl revised this gist Dec 24, 2016. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions Vim_pushing_buil-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -49,7 +49,7 @@ The pattern and the line number can't be known in advance, of course, but we can

    ## Steps 1 and 3

    Starting with `:g/pattern/#<CR>`, it's relatively easy to come up with a simple mapping:
    This is the easiest (and thus most boring) part. Starting with `:g/pattern/#<CR>`, it's relatively easy to come up with a simple mapping:

    nnoremap <key> :g//#<Left><Left>

    @@ -61,7 +61,7 @@ Executing our search is now reduced to `<key>` + pattern + `<CR>`, which is not

    ## Step 4

    This problem is a bit more complex but it's very doable with a bit of straightforward vimscript:
    This problem is a bit more complex (and thus a lot more interesting) but it's very doable with a bit of straightforward vimscript:

    function! CCR()
    " grab the current command-line
    @@ -103,7 +103,7 @@ Well, we already have a solid foundation, so let's augment it a bit:

    This seems to work: pressing `<CR>` after any of those commands executes the command *and* populates the command-line with a minimalist prompt. Another achievement unloc… Wait! Wait! Wait! Nope. That's actually a super dumb way to treat our "problem"!

    Why? Because all of those commands actually have different prompts. Sure `#` being all about listing lines, the only reasonable prompt is a colon, but `:ls` lists buffers so the right prompt is `:b`, `:changes` lists entries in the change list so the right prompt is `:norm! g;`, and so on. Don't panic! We only have to add a bunch of conditions to our test. That's all.
    Why? Because those commands actually have different prompts. Sure `:#` being all about listing lines, the only reasonable prompt is a colon, but `:ls` lists buffers so the right prompt would be `:b`, `:changes` lists entries in the change list so the right prompt would be `:norm! g;`, and so on. Don't panic! We only have to add a bunch of conditions to our test. That's all.

    Hmm… and figure out the right prompt for each command:

    @@ -123,7 +123,7 @@ Hmm… and figure out the right prompt for each command:

    Yeah, some of those prompts are a bit unintuitive and/or require quite a lot of typing. That's one more reason for streamlining the whole thing, right?

    One more thing to consider is how Vim orders items in those lists and how long they can be. The lists generated by `:#`, `:ls`, `:ilist`, `:dlist`, `:clist`, `:llist`, or `:marks` are relatively short but those generated by `:jumps`, `:oldfiles`, or `:changes` can be 100 lines long and require paging. This can be really cumbersome, especially considering that the most recent items are near *the end* of the list. For this reason, I chose to temporarily `:set nomore` in order to jump directly to the end of the list. This is not as clean as I would like it to be but well…
    One more thing to consider is how Vim orders items in those lists and how long the list can be. The lists generated by `:#`, `:ls`, `:ilist`, `:dlist`, `:clist`, `:llist`, or `:marks` are relatively short but those generated by `:jumps`, `:oldfiles`, or `:changes` can be 100 lines long and require paging. This can be really cumbersome, especially considering that the most recent items are near *the end* of the list. For this reason, I chose to temporarily `:set nomore` in order to jump directly to the end of the list. This is not as clean as I would like it to be but well…

    And now, the glorious (and commented) result:

    @@ -170,6 +170,6 @@ Basically, that mapping and its associated function don't really change anything

    OK, but we still have only **one** mapping for `:g//#`. What about the other commands?

    Sure we could go on a hunt for available keys and create mappings for just about every command but that will make a lot to remember for commands we don't use that much anyway. Instead, let's consider this function and this command-line mode mapping as "enablers" that make using those list-like commands a lot easier.
    Sure we could go on a hunt for available keys and create mappings for just about every list-like command but that will make a lot to remember for commands we don't use that much anyway. Instead, let's consider this function and this command-line mode mapping as "enablers" that make using those list-like commands a lot easier.

    If we notice one such command creeping into our workflow, well… we will map it!
  7. romainl revised this gist Dec 5, 2016. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions Vim_pushing_buil-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -11,23 +11,23 @@ The first search commands we learn are usually `/` and `?`. These are seriously

    A better candidate for those situations would be the awesome `:g[lobal]/pattern/command` but it uses the `:p[rint]` command by default, which is not that useful:

    :g/foo
    :g/foo<CR>
    fqjsfd foo
    foo dhqdgqs
    // foo shdjfksgdf
    Press ENTER or type command to continue

    With `:#` (or `:nu[mber]`), we ask Vim to also display the line numbers:

    :g/foo/#
    :g/foo/#<CR>
    3 fqjsfd foo
    12 foo dhqdgqs
    13 // foo shdjfksgdf
    Press ENTER or type command to continue

    that we can use at the prompt:

    :12
    :12<CR>

    to jump to the desired line.

  8. romainl revised this gist Dec 4, 2016. 1 changed file with 31 additions and 13 deletions.
    44 changes: 31 additions & 13 deletions Vim_pushing_buil-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -2,10 +2,10 @@

    Searching can be an efficient way to navigate the current buffer.

    The first search commands you learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine your search pattern. But `/` and `?` really shine when all you want is to jump to something you already have your eyeballs on but they are not fit for *every* situation:
    The first search commands we learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine our search pattern. But `/` and `?` really shine when all we want is to jump to something we already have our eyeballs on but they are not fit for *every* situation:

    * when you want to search something that's not directly *there*, those two commands can make you loose context very quickly,
    * when you need to compare the matches.
    * when we want to search something that's not directly *there*, those two commands can make us loose context very quickly,
    * when we need to compare the matches.

    # A better way

    @@ -17,31 +17,38 @@ A better candidate for those situations would be the awesome `:g[lobal]/pattern/
    // foo shdjfksgdf
    Press ENTER or type command to continue

    With `:#` (or `:nu[mber]`), we ask Vim to also display the line numbers that we can then use at the prompt:
    With `:#` (or `:nu[mber]`), we ask Vim to also display the line numbers:

    :g/foo/#
    3 fqjsfd foo
    12 foo dhqdgqs
    13 // foo shdjfksgdf
    Press ENTER or type command to continue

    that we can use at the prompt:

    :12

    to jump to the desired line.

    This doesn't look like much but `:g/pattern/#` is an immensely useful tool that deserves its place in everyone's toolbox. No setup, no dependency, no third-party plugin… it just works!

    And will always do.
    And will *always* do.

    # A *better* better way

    As is, this command requires us to type:

    * `:g/` before our `pattern`,
    * `/#<CR>` after our `pattern`,
    * and `:` followed by 1 to infinite digits, folowed by `<CR>`.
    1. `:g/`,
    2. our `pattern`,
    3. `/#<CR>`,
    4. `:` followed by 1 to infinite digits,
    5. `<CR>`.

    The pattern and the line number can't be known in advance, of course, but we can certainly simplify the rest.

    ## Steps 1 and 3

    Starting with `:g/pattern/#<CR>`, it's relatively easy to come up with a simple mapping:

    nnoremap <key> :g//#<Left><Left>
    @@ -52,16 +59,25 @@ that populates the command-line with a command stub and moves the cursor between

    Executing our search is now reduced to `<key>` + pattern + `<CR>`, which is not bad at all. But what about the prompt? What if we could reduce that `:` + digits + `<CR>` part?

    ## Step 4

    This problem is a bit more complex but it's very doable with a bit of straightforward vimscript:

    function! CCR()
    " grab the current command-line
    let cmdline = getcmdline()
    " does it end with '#' or 'number' or one of its abbreviations?
    if cmdline =~ '\v\C/(#|nu|num|numb|numbe|number)$'
    " press '<CR>' then ':' to enter command-line mode
    return "\<CR>:"
    else
    " press '<CR>'
    return "\<CR>"
    endif
    endfunction

    " map '<CR>' in command-line mode to execute the function above
    cnoremap <expr> <CR> CCR()

    The idea is to automatize the `<CR>` then `:` sequence when the command we typed (or ran through a mapping) ends with `/#` or any abbreviation of `/nu[mber]`.
    @@ -70,7 +86,7 @@ We are now down to `<key>` + pattern + `<CR>` + digits + `<CR>`. Yes, that's a "

    # Generalizing

    Sure, streamlining that boring (but mighty) `:g/foo/#<CR>:17<CR>` was quite an achievement but we learned a lot of similar list-like commands in the meantime: `:ls`, `:changes`, `:ilist` and so on. What if we could add an automatic prompt for *all of them*?
    Sure, streamlining that boring (but mighty) `:g/foo/#<CR>:17<CR>` was quite an achievement but we undoubtedly learned a lot of similar list-like commands in the meantime: `:ls`, `:changes`, `:ilist` and so on. Creating a common mapping for all those commands is obviously out of question but… what if we could add an automatic prompt for *all of them*?

    Well, we already have a solid foundation, so let's augment it a bit:

    @@ -105,7 +121,7 @@ Hmm… and figure out the right prompt for each command:
    | `:marks` | `:norm[al]! '*` |
    | `:undol[ist]` | `:u[ndo] *` |

    Yeah, some of those are a bit unintuitive and/or require quite a lot of typing. That's one more reason for streamlining the whole thing, right?
    Yeah, some of those prompts are a bit unintuitive and/or require quite a lot of typing. That's one more reason for streamlining the whole thing, right?

    One more thing to consider is how Vim orders items in those lists and how long they can be. The lists generated by `:#`, `:ls`, `:ilist`, `:dlist`, `:clist`, `:llist`, or `:marks` are relatively short but those generated by `:jumps`, `:oldfiles`, or `:changes` can be 100 lines long and require paging. This can be really cumbersome, especially considering that the most recent items are near *the end* of the list. For this reason, I chose to temporarily `:set nomore` in order to jump directly to the end of the list. This is not as clean as I would like it to be but well…

    @@ -150,8 +166,10 @@ And now, the glorious (and commented) result:
    endfunction
    cnoremap <expr> <CR> CCR()

    Basically, that mapping and its associated function don't really change anything fundamental. We still use `:ilist` or `:oldfiles` as we used to, **but we don't have to type a different prompt for every command anymore.** All we did was reducing friction and have a lot of fun in the process.
    Basically, that mapping and its associated function don't really change anything fundamental. We still use `:ilist` or `:oldfiles` as we used to, **but we don't have to type (and remember) a different prompt for every command anymore.** All we did was reducing friction and have a lot of fun in the process.

    OK, but we still have only **one** mapping for `:g//#`. What about the other commands?

    OK, but we still have only **one** mapping, for `:g//#`. Why don't we create mappings for all those commands?
    Sure we could go on a hunt for available keys and create mappings for just about every command but that will make a lot to remember for commands we don't use that much anyway. Instead, let's consider this function and this command-line mode mapping as "enablers" that make using those list-like commands a lot easier.

    Sure you can go on a hunt for available keys and create mappings for just about every command but that will make a lot to remember for commands you don't use that much anyway. Instead, consider this function and this command-line mode mapping as "enablers" that make using those list-like commands a lot easier. If you notice one such command creeping into your workflow, well… map it!
    If we notice one such command creeping into our workflow, well… we will map it!
  9. romainl revised this gist Dec 4, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Vim_pushing_buil-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    Searching can be an efficient way to navigate the current buffer.

    The first search commands you learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine our search pattern. But `/` and `?` really shine when all you want is to jump to something you already have your eyeballs on but they are not fit for *every* situation:
    The first search commands you learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine your search pattern. But `/` and `?` really shine when all you want is to jump to something you already have your eyeballs on but they are not fit for *every* situation:

    * when you want to search something that's not directly *there*, those two commands can make you loose context very quickly,
    * when you need to compare the matches.
  10. romainl revised this gist Dec 3, 2016. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions Vim_pushing_buil-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@ Searching can be an efficient way to navigate the current buffer.
    The first search commands you learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine our search pattern. But `/` and `?` really shine when all you want is to jump to something you already have your eyeballs on but they are not fit for *every* situation:

    * when you want to search something that's not directly *there*, those two commands can make you loose context very quickly,
    * when you need to be able to compare the matches.
    * when you need to compare the matches.

    # A better way

    @@ -50,7 +50,7 @@ that populates the command-line with a command stub and moves the cursor between

    :g/|/#

    Executing our search is now reduced to `<key>` + pattern + `<CR>`, which is not bad at all. But what about the prompt? What if we could reduce `:` + digits + `<CR>`?
    Executing our search is now reduced to `<key>` + pattern + `<CR>`, which is not bad at all. But what about the prompt? What if we could reduce that `:` + digits + `<CR>` part?

    This problem is a bit more complex but it's very doable with a bit of straightforward vimscript:

    @@ -105,7 +105,7 @@ Hmm… and figure out the right prompt for each command:
    | `:marks` | `:norm[al]! '*` |
    | `:undol[ist]` | `:u[ndo] *` |

    Yeah, some of those are a bit unintuitive. That's one more reason for streamlining the whole thing, right?
    Yeah, some of those are a bit unintuitive and/or require quite a lot of typing. That's one more reason for streamlining the whole thing, right?

    One more thing to consider is how Vim orders items in those lists and how long they can be. The lists generated by `:#`, `:ls`, `:ilist`, `:dlist`, `:clist`, `:llist`, or `:marks` are relatively short but those generated by `:jumps`, `:oldfiles`, or `:changes` can be 100 lines long and require paging. This can be really cumbersome, especially considering that the most recent items are near *the end* of the list. For this reason, I chose to temporarily `:set nomore` in order to jump directly to the end of the list. This is not as clean as I would like it to be but well…

    @@ -154,4 +154,4 @@ Basically, that mapping and its associated function don't really change anything

    OK, but we still have only **one** mapping, for `:g//#`. Why don't we create mappings for all those commands?

    Sure you can go on a hunt for available keys and create mappings for just about every command but that will make a lot to remember for commands you don't use that much anyway.
    Sure you can go on a hunt for available keys and create mappings for just about every command but that will make a lot to remember for commands you don't use that much anyway. Instead, consider this function and this command-line mode mapping as "enablers" that make using those list-like commands a lot easier. If you notice one such command creeping into your workflow, well… map it!
  11. romainl revised this gist Nov 17, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Vim_pushing_buil-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ Searching can be an efficient way to navigate the current buffer.

    The first search commands you learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine our search pattern. But `/` and `?` really shine when all you want is to jump to something you already have your eyeballs on but they are not fit for *every* situation:

    * when you want to search something that's not directly there, those two commands can make you loose context very quickly,
    * when you want to search something that's not directly *there*, those two commands can make you loose context very quickly,
    * when you need to be able to compare the matches.

    # A better way
  12. romainl revised this gist Nov 13, 2016. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions Vim_pushing_buil-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -107,6 +107,8 @@ Hmm… and figure out the right prompt for each command:

    Yeah, some of those are a bit unintuitive. That's one more reason for streamlining the whole thing, right?

    One more thing to consider is how Vim orders items in those lists and how long they can be. The lists generated by `:#`, `:ls`, `:ilist`, `:dlist`, `:clist`, `:llist`, or `:marks` are relatively short but those generated by `:jumps`, `:oldfiles`, or `:changes` can be 100 lines long and require paging. This can be really cumbersome, especially considering that the most recent items are near *the end* of the list. For this reason, I chose to temporarily `:set nomore` in order to jump directly to the end of the list. This is not as clean as I would like it to be but well…

    And now, the glorious (and commented) result:

    " make list-like commands more intuitive
  13. romainl revised this gist Nov 12, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Vim_pushing_buil-in_features_beyond_their_limits.markdown
    Original file line number Diff line number Diff line change
    @@ -85,7 +85,7 @@ Well, we already have a solid foundation, so let's augment it a bit:
    endif
    endfunction

    This seems to work: pressing `<CR>` after any of those commands executes the command *and* populates the command-line with a minimalist prompt. Another achievement unloc… Wait! Wait! Wait! Nope. That's acually a super dumb way to treat our "problem"!
    This seems to work: pressing `<CR>` after any of those commands executes the command *and* populates the command-line with a minimalist prompt. Another achievement unloc… Wait! Wait! Wait! Nope. That's actually a super dumb way to treat our "problem"!

    Why? Because all of those commands actually have different prompts. Sure `#` being all about listing lines, the only reasonable prompt is a colon, but `:ls` lists buffers so the right prompt is `:b`, `:changes` lists entries in the change list so the right prompt is `:norm! g;`, and so on. Don't panic! We only have to add a bunch of conditions to our test. That's all.

  14. romainl renamed this gist Nov 12, 2016. 1 changed file with 0 additions and 0 deletions.
  15. romainl renamed this gist Nov 12, 2016. 1 changed file with 0 additions and 0 deletions.
  16. romainl revised this gist Nov 12, 2016. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -23,7 +23,8 @@ With `:#` (or `:nu[mber]`), we ask Vim to also display the line numbers that we
    3 fqjsfd foo
    12 foo dhqdgqs
    13 // foo shdjfksgdf
    :12
    Press ENTER or type command to continue
    :12

    to jump to the desired line.

    @@ -84,7 +85,7 @@ Well, we already have a solid foundation, so let's augment it a bit:
    endif
    endfunction

    This seems to work: pressing `<CR>` after any of those commands executes the command *and* populates the command-line with a prompt. Another achievement unloc… Wait! Wait! Wait! Nope. That's acually a super dumb way to treat our "problem"!
    This seems to work: pressing `<CR>` after any of those commands executes the command *and* populates the command-line with a minimalist prompt. Another achievement unloc… Wait! Wait! Wait! Nope. That's acually a super dumb way to treat our "problem"!

    Why? Because all of those commands actually have different prompts. Sure `#` being all about listing lines, the only reasonable prompt is a colon, but `:ls` lists buffers so the right prompt is `:b`, `:changes` lists entries in the change list so the right prompt is `:norm! g;`, and so on. Don't panic! We only have to add a bunch of conditions to our test. That's all.

    @@ -104,9 +105,9 @@ Hmm… and figure out the right prompt for each command:
    | `:marks` | `:norm[al]! '*` |
    | `:undol[ist]` | `:u[ndo] *` |

    Yeah, some of those are a bit unintuitive. That's one more reason for streamlining the whole thing, isn't it?
    Yeah, some of those are a bit unintuitive. That's one more reason for streamlining the whole thing, right?

    And now, the glorious result:
    And now, the glorious (and commented) result:

    " make list-like commands more intuitive
    function! CCR()
  17. romainl revised this gist Nov 12, 2016. 1 changed file with 5 additions and 2 deletions.
    7 changes: 5 additions & 2 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -101,9 +101,12 @@ Hmm… and figure out the right prompt for each command:
    | `:old[files]` | `:e[dit] #<*` |
    | `:changes` | `:norm[al]! *g;` |
    | `:ju[mps]` | `:norm[al]! *<C-o>` |
    | `:marks` | `:norm[al]! ```*` |
    | `:marks` | `:norm[al]! '*` |
    | `:undol[ist]` | `:u[ndo] *` |

    The glorious result:
    Yeah, some of those are a bit unintuitive. That's one more reason for streamlining the whole thing, isn't it?

    And now, the glorious result:

    " make list-like commands more intuitive
    function! CCR()
  18. romainl revised this gist Nov 12, 2016. 1 changed file with 1 addition and 13 deletions.
    14 changes: 1 addition & 13 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -101,19 +101,7 @@ Hmm… and figure out the right prompt for each command:
    | `:old[files]` | `:e[dit] #<*` |
    | `:changes` | `:norm[al]! *g;` |
    | `:ju[mps]` | `:norm[al]! *<C-o>` |
    | `:marks` | `:norm[al]! ``*` |

    | sqsqs | qsqsqs |
    |---|---|
    | qsq | qsqsqs |
    | qsqs | qsqsqs |
    | qsqsqsqsqs | qsqsqs |
    | qsqsqs | qsqsqsqs |
    | qsqs | qsqs |
    | qsqs | qsqsqsqsqs |
    | qsqs | qsqs |
    | qsqsqsqs | qsqs |
    | qsqsqs | qsqsqs |
    | `:marks` | `:norm[al]! ```*` |

    The glorious result:

  19. romainl revised this gist Nov 12, 2016. 1 changed file with 11 additions and 11 deletions.
    22 changes: 11 additions & 11 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -90,18 +90,18 @@ Why? Because all of those commands actually have different prompts. Sure `#` bei

    Hmm… and figure out the right prompt for each command:

    | Command | Prompt (`|` marks the desired cursor position) |
    | Command | Prompt (`*` marks the desired cursor position) |
    |-----------------------------|------------------------------------------------|
    | `:#`, `:nu[mber]` | `:|` |
    | `:ls`, `:files`, `:buffers` | `:b|` |
    | `:il[ist]` | `:ij[ump] | pattern` |
    | `:dli[st]` | `:dj[ump] | pattern` |
    | `:cl[ist]` | `:cc |` |
    | `:lli[st]` | `:ll |` |
    | `:old[files]` | `:e[dit] #<|` |
    | `:changes` | `:norm[al]! |g;` |
    | `:ju[mps]` | `:norm[al]! |<C-o>` |
    | `:marks` | `:norm[al]! |` |
    | `:#`, `:nu[mber]` | `:*` |
    | `:ls`, `:files`, `:buffers` | `:b*` |
    | `:il[ist]` | `:ij[ump] * pattern` |
    | `:dli[st]` | `:dj[ump] * pattern` |
    | `:cl[ist]` | `:cc *` |
    | `:lli[st]` | `:ll *` |
    | `:old[files]` | `:e[dit] #<*` |
    | `:changes` | `:norm[al]! *g;` |
    | `:ju[mps]` | `:norm[al]! *<C-o>` |
    | `:marks` | `:norm[al]! ``*` |

    | sqsqs | qsqsqs |
    |---|---|
  20. romainl revised this gist Nov 12, 2016. 1 changed file with 12 additions and 12 deletions.
    24 changes: 12 additions & 12 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -90,18 +90,18 @@ Why? Because all of those commands actually have different prompts. Sure `#` bei

    Hmm… and figure out the right prompt for each command:

    | Command | Prompt (`|` marks the desired cursor position) |
    |----------------------------|------------------------------------------------|
    |`:#`, `:nu[mber]` | `:|` |
    |`:ls`, `:files`, `:buffers` | `:b|` |
    |`:il[ist]` | `:ij[ump] | pattern` |
    |`:dli[st]` | `:dj[ump] | pattern` |
    |`:cl[ist]` | `:cc |` |
    |`:lli[st]` | `:ll |` |
    |`:old[files]` | `:e[dit] #<|` |
    |`:changes` | `:norm[al]! |g;` |
    |`:ju[mps]` | `:norm[al]! |<C-o>` |
    |`:marks` | `:norm[al]! |` |
    | Command | Prompt (`|` marks the desired cursor position) |
    |-----------------------------|------------------------------------------------|
    | `:#`, `:nu[mber]` | `:|` |
    | `:ls`, `:files`, `:buffers` | `:b|` |
    | `:il[ist]` | `:ij[ump] | pattern` |
    | `:dli[st]` | `:dj[ump] | pattern` |
    | `:cl[ist]` | `:cc |` |
    | `:lli[st]` | `:ll |` |
    | `:old[files]` | `:e[dit] #<|` |
    | `:changes` | `:norm[al]! |g;` |
    | `:ju[mps]` | `:norm[al]! |<C-o>` |
    | `:marks` | `:norm[al]! |` |

    | sqsqs | qsqsqs |
    |---|---|
  21. romainl revised this gist Nov 12, 2016. 1 changed file with 12 additions and 0 deletions.
    12 changes: 12 additions & 0 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -103,6 +103,18 @@ Hmm… and figure out the right prompt for each command:
    |`:ju[mps]` | `:norm[al]! |<C-o>` |
    |`:marks` | `:norm[al]! |` |

    | sqsqs | qsqsqs |
    |---|---|
    | qsq | qsqsqs |
    | qsqs | qsqsqs |
    | qsqsqsqsqs | qsqsqs |
    | qsqsqs | qsqsqsqs |
    | qsqs | qsqs |
    | qsqs | qsqsqsqsqs |
    | qsqs | qsqs |
    | qsqsqsqs | qsqs |
    | qsqsqs | qsqsqs |

    The glorious result:

    " make list-like commands more intuitive
  22. romainl revised this gist Nov 12, 2016. 1 changed file with 12 additions and 12 deletions.
    24 changes: 12 additions & 12 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -90,18 +90,18 @@ Why? Because all of those commands actually have different prompts. Sure `#` bei

    Hmm… and figure out the right prompt for each command:

    |Command | Prompt (`|` marks the desired cursor position)|
    |----------------------------|-----------------------------------------------|
    |`:#`, `:nu[mber]` | `:|` |
    |`:ls`, `:files`, `:buffers` | `:b|` |
    |`:il[ist]` | `:ij[ump] | pattern` |
    |`:dli[st]` | `:dj[ump] | pattern` |
    |`:cl[ist]` | `:cc |` |
    |`:lli[st]` | `:ll |` |
    |`:old[files]` | `:e[dit] #<|` |
    |`:changes` | `:norm[al]! |g;` |
    |`:ju[mps]` | `:norm[al]! |<C-o>` |
    |`:marks` | `:norm[al]! |` |
    | Command | Prompt (`|` marks the desired cursor position) |
    |----------------------------|------------------------------------------------|
    |`:#`, `:nu[mber]` | `:|` |
    |`:ls`, `:files`, `:buffers` | `:b|` |
    |`:il[ist]` | `:ij[ump] | pattern` |
    |`:dli[st]` | `:dj[ump] | pattern` |
    |`:cl[ist]` | `:cc |` |
    |`:lli[st]` | `:ll |` |
    |`:old[files]` | `:e[dit] #<|` |
    |`:changes` | `:norm[al]! |g;` |
    |`:ju[mps]` | `:norm[al]! |<C-o>` |
    |`:marks` | `:norm[al]! |` |

    The glorious result:

  23. romainl revised this gist Nov 12, 2016. 1 changed file with 12 additions and 12 deletions.
    24 changes: 12 additions & 12 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -90,18 +90,18 @@ Why? Because all of those commands actually have different prompts. Sure `#` bei

    Hmm… and figure out the right prompt for each command:

    Command | Prompt (`|` marks the desired cursor position)
    ----------------------------|-----------------------------------------------
    `:#`, `:nu[mber]` | `:|`
    `:ls`, `:files`, `:buffers` | `:b|`
    `:il[ist]` | `:ij[ump] | pattern`
    `:dli[st]` | `:dj[ump] | pattern`
    `:cl[ist]` | `:cc |`
    `:lli[st]` | `:ll |`
    `:old[files]` | `:e[dit] #<|`
    `:changes` | `:norm[al]! |g;`
    `:ju[mps]` | `:norm[al]! |<C-o>`
    `:marks` | `:norm[al]! ``|`
    |Command | Prompt (`|` marks the desired cursor position)|
    |----------------------------|-----------------------------------------------|
    |`:#`, `:nu[mber]` | `:|` |
    |`:ls`, `:files`, `:buffers` | `:b|` |
    |`:il[ist]` | `:ij[ump] | pattern` |
    |`:dli[st]` | `:dj[ump] | pattern` |
    |`:cl[ist]` | `:cc |` |
    |`:lli[st]` | `:ll |` |
    |`:old[files]` | `:e[dit] #<|` |
    |`:changes` | `:norm[al]! |g;` |
    |`:ju[mps]` | `:norm[al]! |<C-o>` |
    |`:marks` | `:norm[al]! |` |

    The glorious result:

  24. romainl revised this gist Nov 12, 2016. 1 changed file with 16 additions and 1 deletion.
    17 changes: 16 additions & 1 deletion limits.markdown
    Original file line number Diff line number Diff line change
    @@ -88,7 +88,22 @@ This seems to work: pressing `<CR>` after any of those commands executes the com

    Why? Because all of those commands actually have different prompts. Sure `#` being all about listing lines, the only reasonable prompt is a colon, but `:ls` lists buffers so the right prompt is `:b`, `:changes` lists entries in the change list so the right prompt is `:norm! g;`, and so on. Don't panic! We only have to add a bunch of conditions to our test. That's all.

    Hmm… and figure out the right prompt for each command. I'll save you the details (or detail them if you want) and go straight to the result:
    Hmm… and figure out the right prompt for each command:

    Command | Prompt (`|` marks the desired cursor position)
    ----------------------------|-----------------------------------------------
    `:#`, `:nu[mber]` | `:|`
    `:ls`, `:files`, `:buffers` | `:b|`
    `:il[ist]` | `:ij[ump] | pattern`
    `:dli[st]` | `:dj[ump] | pattern`
    `:cl[ist]` | `:cc |`
    `:lli[st]` | `:ll |`
    `:old[files]` | `:e[dit] #<|`
    `:changes` | `:norm[al]! |g;`
    `:ju[mps]` | `:norm[al]! |<C-o>`
    `:marks` | `:norm[al]! ``|`

    The glorious result:

    " make list-like commands more intuitive
    function! CCR()
  25. romainl revised this gist Nov 12, 2016. 1 changed file with 6 additions and 2 deletions.
    8 changes: 6 additions & 2 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -49,7 +49,7 @@ that populates the command-line with a command stub and moves the cursor between

    :g/|/#

    Executing our search is now reduced to `<key>` + pattern + `<CR>`, which is not bad at all. But what about the prompt? What if we could reduce `:` + 10000 + `<CR>`?
    Executing our search is now reduced to `<key>` + pattern + `<CR>`, which is not bad at all. But what about the prompt? What if we could reduce `:` + digits + `<CR>`?

    This problem is a bit more complex but it's very doable with a bit of straightforward vimscript:

    @@ -129,4 +129,8 @@ Hmm… and figure out the right prompt for each command. I'll save you the detai
    endfunction
    cnoremap <expr> <CR> CCR()

    Basically, that mapping and its associated function don't really change anything fundamental. We still use `:ilist` or `:oldfiles` as we used to, **but we don't have to type a different prompt for every command anymore.** All we did was reducing friction and have a lot of fun in the process.
    Basically, that mapping and its associated function don't really change anything fundamental. We still use `:ilist` or `:oldfiles` as we used to, **but we don't have to type a different prompt for every command anymore.** All we did was reducing friction and have a lot of fun in the process.

    OK, but we still have only **one** mapping, for `:g//#`. Why don't we create mappings for all those commands?

    Sure you can go on a hunt for available keys and create mappings for just about every command but that will make a lot to remember for commands you don't use that much anyway.
  26. romainl revised this gist Nov 12, 2016. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -9,15 +9,15 @@ The first search commands you learn are usually `/` and `?`. These are seriously

    # A better way

    A better candidate for those situations would be the awesome `:g[lobal]/pattern/command` but it uses the `p[rint]` command by default, which is not that useful:
    A better candidate for those situations would be the awesome `:g[lobal]/pattern/command` but it uses the `:p[rint]` command by default, which is not that useful:

    :g/foo
    fqjsfd foo
    foo dhqdgqs
    // foo shdjfksgdf
    Press ENTER or type command to continue

    By using `:#` (or `:nu[mber]`), we ask Vim to also display the line numbers that we can then use at the prompt:
    With `:#` (or `:nu[mber]`), we ask Vim to also display the line numbers that we can then use at the prompt:

    :g/foo/#
    3 fqjsfd foo
    @@ -27,7 +27,7 @@ By using `:#` (or `:nu[mber]`), we ask Vim to also display the line numbers that

    to jump to the desired line.

    This doesn't look like much but `:g/pattern/#` is an immensely useful tool that deserves its place in anyone's toolbox. No setup, no dependency, no third-party plugin… it just works!
    This doesn't look like much but `:g/pattern/#` is an immensely useful tool that deserves its place in everyone's toolbox. No setup, no dependency, no third-party plugin… it just works!

    And will always do.

  27. romainl revised this gist Nov 12, 2016. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions limits.markdown
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,4 @@


    # The sitution
    # The situation

    Searching can be an efficient way to navigate the current buffer.

  28. romainl renamed this gist Nov 12, 2016. 1 changed file with 34 additions and 8 deletions.
    42 changes: 34 additions & 8 deletions gistfile1.markdown → limits.markdown
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    Built-in features from low to high level.


    # The sitution

    @@ -29,17 +29,19 @@ By using `:#` (or `:nu[mber]`), we ask Vim to also display the line numbers that

    to jump to the desired line.

    This doesn't look like much but `:g/pattern/#` is an immensely useful tool to have in anyone's toolbox. No setup, no dependency, no third-party plugin… it just works!
    This doesn't look like much but `:g/pattern/#` is an immensely useful tool that deserves its place in anyone's toolbox. No setup, no dependency, no third-party plugin… it just works!

    And will always do.

    # A better better way
    # A *better* better way

    As is, this command requires us to type:

    * `:g/` before our `pattern`,
    * `/#<CR>` after our `pattern`,
    * and `:` followed by 1 to infinite digits, folowed by `<CR>`.

    The pattern and the line number can't be known in advance, of course, be we can certainly simplify the rest.
    The pattern and the line number can't be known in advance, of course, but we can certainly simplify the rest.

    Starting with `:g/pattern/#<CR>`, it's relatively easy to come up with a simple mapping:

    @@ -51,7 +53,7 @@ that populates the command-line with a command stub and moves the cursor between

    Executing our search is now reduced to `<key>` + pattern + `<CR>`, which is not bad at all. But what about the prompt? What if we could reduce `:` + 10000 + `<CR>`?

    This problem is a bit more complex than the other but it's very doable with a bit of vimscript:
    This problem is a bit more complex but it's very doable with a bit of straightforward vimscript:

    function! CCR()
    let cmdline = getcmdline()
    @@ -63,14 +65,35 @@ This problem is a bit more complex than the other but it's very doable with a bi
    endfunction
    cnoremap <expr> <CR> CCR()

    The idea, here, is to automatize the `<CR>` then `:` sequence when the command we typed (or ran through a mapping) ends with `/#` or any abbreviation of `/number`.
    The idea is to automatize the `<CR>` then `:` sequence when the command we typed (or ran through a mapping) ends with `/#` or any abbreviation of `/nu[mber]`.

    We are now down to `<key>` + pattern + `<CR>` + digits + `<CR>`. Yes. That's only **three** motherfucking keystrokes for the whole process!
    We are now down to `<key>` + pattern + `<CR>` + digits + `<CR>`. Yes, that's a "core" of only **three** motherfucking keystrokes for the whole process!

    # Generalizing

    Sure, streamlining that boring (but mighty) `:g/foo/#<CR>:17<CR>` was quite an achievement but we learned a lot of similar list-like commands in the meantime: `:ls`, `:changes`, `:ilist` and so on. What if we could add an automatic prompt for *all of them*?

    Well, we already have a solid foundation, so let's augment it a bit:

    function! CCR()
    let cmdline = getcmdline()
    if cmdline =~ '\v\C/(#|nu|num|numb|numbe|number)$'
    return "\<CR>:"
    elseif cmdline =~ '\v\C^(ls|files|buffers|dli|il|cli|lli|old|changes|ju|marks|undol)'
    return "\<CR>:"
    else
    return "\<CR>"
    endif
    endfunction

    This seems to work: pressing `<CR>` after any of those commands executes the command *and* populates the command-line with a prompt. Another achievement unloc… Wait! Wait! Wait! Nope. That's acually a super dumb way to treat our "problem"!

    Why? Because all of those commands actually have different prompts. Sure `#` being all about listing lines, the only reasonable prompt is a colon, but `:ls` lists buffers so the right prompt is `:b`, `:changes` lists entries in the change list so the right prompt is `:norm! g;`, and so on. Don't panic! We only have to add a bunch of conditions to our test. That's all.

    Hmm… and figure out the right prompt for each command. I'll save you the details (or detail them if you want) and go straight to the result:

    " make list-like commands more intuitive
    function! ccr#CCR()
    function! CCR()
    let cmdline = getcmdline()
    if cmdline =~ '\v\C^(ls|files|buffers)'
    " like :ls but prompts for a buffer command
    @@ -106,3 +129,6 @@ We are now down to `<key>` + pattern + `<CR>` + digits + `<CR>`. Yes. That's onl
    return "\<CR>"
    endif
    endfunction
    cnoremap <expr> <CR> CCR()

    Basically, that mapping and its associated function don't really change anything fundamental. We still use `:ilist` or `:oldfiles` as we used to, **but we don't have to type a different prompt for every command anymore.** All we did was reducing friction and have a lot of fun in the process.
  29. romainl revised this gist Nov 12, 2016. 1 changed file with 10 additions and 2 deletions.
    12 changes: 10 additions & 2 deletions gistfile1.markdown
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,16 @@
    Built-in features from low to high level.

    # The sitution

    Searching can be an efficient way to navigate the current buffer.

    The first search commands you learn are usually `/` and `?`. These are seriously cool, especially with the `incsearch` option enabled which lets us keep typing to refine our search pattern. But `/` and `?` really shine when all you want is to jump to something you already have your eyeballs on but they are not fit for *every* situation:

    * when you want to search something that's not directly there, those two commands can make you loose context very quickly,
    * when you need to be able to compare the matches.

    # A better way

    A better candidate for those situations would be the awesome `:g[lobal]/pattern/command` but it uses the `p[rint]` command by default, which is not that useful:

    :g/foo
    @@ -27,7 +31,9 @@ to jump to the desired line.

    This doesn't look like much but `:g/pattern/#` is an immensely useful tool to have in anyone's toolbox. No setup, no dependency, no third-party plugin… it just works!

    As is, this commands requires us to type:
    # A better better way

    As is, this command requires us to type:

    * `:g/` before our `pattern`,
    * `/#<CR>` after our `pattern`,
    @@ -59,7 +65,9 @@ This problem is a bit more complex than the other but it's very doable with a bi

    The idea, here, is to automatize the `<CR>` then `:` sequence when the command we typed (or ran through a mapping) ends with `/#` or any abbreviation of `/number`.

    We are now down to `<key>` + pattern + `<CR>` + digits + `<CR>`. That's **three** motherfucking keystrokes!
    We are now down to `<key>` + pattern + `<CR>` + digits + `<CR>`. Yes. That's only **three** motherfucking keystrokes for the whole process!

    # Generalizing

    " make list-like commands more intuitive
    function! ccr#CCR()
  30. romainl revised this gist Nov 12, 2016. 1 changed file with 39 additions and 15 deletions.
    54 changes: 39 additions & 15 deletions gistfile1.markdown
    Original file line number Diff line number Diff line change
    @@ -7,27 +7,15 @@ The first search commands you learn are usually `/` and `?`. These are seriously
    * when you want to search something that's not directly there, those two commands can make you loose context very quickly,
    * when you need to be able to compare the matches.

    One way to deal with those situations is to use `:g/foo/#` which lists every line containing `foo`:
    A better candidate for those situations would be the awesome `:g[lobal]/pattern/command` but it uses the `p[rint]` command by default, which is not that useful:

    :g/foo/#
    3 fqjsfd foo
    12 foo dhqdgqs
    13 // foo shdjfksgdf
    Press ENTER or type command to continue

    The awesome `:global` command looks like this:

    :g/pattern/command

    By default, `:global` behaves as if you used the `:print` command, which is not that useful:

    :g/foo/#
    :g/foo
    fqjsfd foo
    foo dhqdgqs
    // foo shdjfksgdf
    Press ENTER or type command to continue

    By using `:#` (or `:nu[mbers]), we ask Vim to also display the line numbers that we can then use at the prompt:
    By using `:#` (or `:nu[mber]`), we ask Vim to also display the line numbers that we can then use at the prompt:

    :g/foo/#
    3 fqjsfd foo
    @@ -37,6 +25,42 @@ By using `:#` (or `:nu[mbers]), we ask Vim to also display the line numbers that

    to jump to the desired line.

    This doesn't look like much but `:g/pattern/#` is an immensely useful tool to have in anyone's toolbox. No setup, no dependency, no third-party plugin… it just works!

    As is, this commands requires us to type:

    * `:g/` before our `pattern`,
    * `/#<CR>` after our `pattern`,
    * and `:` followed by 1 to infinite digits, folowed by `<CR>`.

    The pattern and the line number can't be known in advance, of course, be we can certainly simplify the rest.

    Starting with `:g/pattern/#<CR>`, it's relatively easy to come up with a simple mapping:

    nnoremap <key> :g//#<Left><Left>

    that populates the command-line with a command stub and moves the cursor between the slashes, ready for us to type the pattern and press `<CR>`:

    :g/|/#

    Executing our search is now reduced to `<key>` + pattern + `<CR>`, which is not bad at all. But what about the prompt? What if we could reduce `:` + 10000 + `<CR>`?

    This problem is a bit more complex than the other but it's very doable with a bit of vimscript:

    function! CCR()
    let cmdline = getcmdline()
    if cmdline =~ '\v\C/(#|nu|num|numb|numbe|number)$'
    return "\<CR>:"
    else
    return "\<CR>"
    endif
    endfunction
    cnoremap <expr> <CR> CCR()

    The idea, here, is to automatize the `<CR>` then `:` sequence when the command we typed (or ran through a mapping) ends with `/#` or any abbreviation of `/number`.

    We are now down to `<key>` + pattern + `<CR>` + digits + `<CR>`. That's **three** motherfucking keystrokes!

    " make list-like commands more intuitive
    function! ccr#CCR()
    let cmdline = getcmdline()