Code Monkey home page Code Monkey logo

targets.vim's Introduction

Introduction

Targets.vim is a Vim plugin that adds various text objects to give you more targets to operate on. It expands on the idea of simple commands like di' (delete inside the single quotes around the cursor) to give you more opportunities to craft powerful commands that can be repeated reliably. One major goal is to handle all corner cases correctly.

Table of Contents

Click here to show.

Installation

Plugin Manager Command
NeoBundle NeoBundle 'wellle/targets.vim'
Vundle Bundle 'wellle/targets.vim'
Vim-plug Plug 'wellle/targets.vim'
Pathogen git clone git://github.com/wellle/targets.vim.git ~/.vim/bundle/targets.vim
Dein call dein#add('wellle/targets.vim')

Examples

The following examples are displayed as three lines each. The top line denotes cursor positions from where the presented command works. The middle line shows the contents of the example line that we're working on. The last line shows the part of the line that the command will operate on.

To change the text in the next pair of parentheses, use the cin) command

cursor position │    .....................
buffer line     │    This is example text (with a pair of parentheses).
selection       │                          └───────── cin) ─────────┘

To delete the item in a comma separated list under the cursor, use da,

cursor position │                                  .........
buffer line     │    Shopping list: oranges, apples, bananas, tomatoes
selection       │                                  └─ da, ─┘

Notice how the selection includes exactly one of the surrounding commas to leave a proper comma separated list behind.

Overview

Targets.vim comes with five kinds for text objects:

  • Pair text objects
  • Quote text objects
  • Separator text objects
  • Argument text objects
  • Tag text objects

Each of those kinds is implemented by a targets source. Third party plugins can provide additional sources to add even more text objects which behave like the built in ones. See plugins for details on how to implement your own targets source.

Pair Text Objects

These text objects are similar to the built in text objects such as i). Supported trigger characters:

  • ( ) (work on parentheses)
  • { } B (work on curly braces)
  • [ ] (work on square brackets)
  • < > (work on angle brackets)
  • t (work on tags)

Pair text objects work over multiple lines and support seeking. See below for details about seeking.

The following examples will use parentheses, but they all work for each listed trigger character accordingly.

In Pair

i( i) i{ i} iB i[ i] i< i> it

  • Select inside of pair characters.
  • This overrides Vim's default text object to allow seeking for the next pair in the current line to the right or left when the cursor is not inside a pair. This behavior is similar to Vim's seeking behavior of di' when not inside of quotes, but it works both ways.
  • Accepts a count to select multiple blocks.
      ............
a ( b ( cccccccc ) d ) e
   │   └── i) ──┘   │
   └───── 2i) ──────┘

A Pair

a( a) a{ a} aB a[ a] a< a> at

  • Select a pair including pair characters.
  • Overrides Vim's default text object to allow seeking.
  • Accepts a count.
      ............
a ( b ( cccccccc ) d ) e
  │   └─── a) ───┘   │
  └────── 2a) ───────┘

Inside Pair

I( I) I{ I} IB I[ I] I< I> It

  • Select contents of pair characters.
  • Like inside of parentheses, but exclude whitespace at both ends. Useful for changing contents while preserving spacing.
  • Accepts a count.
      ............
a ( b ( cccccccc ) d ) e
    │   └─ I) ─┘   │
    └──── 2I) ─────┘

Around Pair

A( A) A{ A} AB A[ A] A< A> At

  • Select around pair characters.
  • Like a pair, but include whitespace at one side of the pair. Prefers to select trailing whitespace, falls back to select leading whitespace.
  • Accepts a count.
      ............
a ( b ( cccccccc ) d ) e
  │   └─── A) ────┘   │
  └────── 2A) ────────┘

Next and Last Pair

in( an( In( An( il( al( Il( Al( ...

Work directly on distant pairs without moving there separately.

All the above pair text objects can be shifted to the next pair by including the letter n. The command in) selects inside of the next pair. Use the letter l instead to work on the previous (last) pair. Uses a count to skip multiple pairs. Skipping works over multiple lines.

See our Cheat Sheet for two charts summarizing all pair mappings.

Pair Seek

If any of the normal pair commands (not containing n or l) is executed when the cursor is not positioned inside a pair, it seeks for pairs before or after the cursor by searching for the appropriate delimiter on the current line. This is similar to using the explicit version containing n or l, but in only seeks on the current line.

Quote Text Objects

These text objects are similar to the built in text objects such as i'. Supported trigger characters:

  • ' (work on single quotes)
  • " (work on double quotes)
  • ` (work on back ticks)

These quote text objects try to be smarter than the default ones. They count the quotation marks from the beginning of the line to decide which of these are the beginning of a quote and which ones are the end.

If you type ci" on the , in the example below, it will automatically skip and change world instead of changing , between hello and world.

buffer │ join("hello", "world")
proper │      └─────┘  └─────┘
false  │            └──┘

Quote text objects work over multiple lines and support seeking. See below for details about seeking.

The following examples will use single quotes, but they all work for each mentioned separator character accordingly.

In Quote

i' i" i`

  • Select inside quote.
  • This overrides Vim's default text object to allow seeking in both directions.
  ............
a ' bbbbbbbb ' c ' d ' e
   └── i' ──┘

A Quote

a' a" a`

  • Select a quote.
  • This overrides Vim's default text object to support seeking.
  • Unlike Vim's quote text objects, this incudes no surrounding whitespace.
  ............
a ' bbbbbbbb ' c ' d ' e
  └─── a' ───┘

Inside Quote

I' I" I`

  • Select contents of a quote.
  • Like inside quote, but exclude whitespace at both ends. Useful for changing contents while preserving spacing.
  ............
a ' bbbbbbbb ' c ' d ' e
    └─ I' ─┘

Around Quote

A' A" A`

  • Select around a quote.
  • Like a quote, but include whitespace in one direction. Prefers to select trailing whitespace, falls back to select leading whitespace.
  ............
a ' bbbbbbbb ' c ' d ' e
  └─── A' ────┘

Next and Last Quote

in' In' An' il' Il' Al' ...

Work directly on distant quotes without moving there separately.

All the above pair text objects can be shifted to the next quote by including the letter n. The command in' selects inside of the next single quotes. Use the letter l instead to work on the previous (last) quote. Uses a count to skip multiple quotation characters.

See our Cheat Sheet for a chart summarizing all quote mappings.

Quote Seek

If any of the normal quote commands (not containing n or l) is executed when the cursor is not positioned inside a quote, it seeks for quotes before or after the cursor by searching for the appropriate delimiter on the current line. This is similar to using the explicit version containing n or l.

Separator Text Objects

These text objects are based on single separator characters like the comma in one of our examples above. The text between two instances of the separator character can be operated on with these targets.

Supported separators:

, . ; : + - = ~ _ * # / | \ & $

Separator text objects work over multiple lines and support seeking.

The following examples will use commas, but they all work for each listed separator character accordingly.

In Separator

i, i. i; i: i+ i- i= i~ i_ i* i# i/ i| i\ i& i$

  • Select inside separators. Similar to in quote.
      ...........
a , b , cccccccc , d , e
       └── i, ──┘

A Separator

a, a. a; a: a+ a- a= a~ a_ a* a# a/ a| a\ a& a$

  • Select an item in a list separated by the separator character.
  • Includes the leading separator, but excludes the trailing one. This leaves a proper list separated by the separator character after deletion. See the examples above.
      ...........
a , b , cccccccc , d , e
      └─── a, ──┘

Inside Separator

I, I. I; I: I+ I- I= I~ I_ I* I# I/ I| I\ I& I$

  • Select contents between separators.
  • Like inside separators, but exclude whitespace at both ends. Useful for changing contents while preserving spacing.
      ...........
a , b , cccccccc , d , e
        └─ I, ─┘

Around Separator

A, A. A; A: A+ A- A= A~ A_ A* A# A/ A| A\ A& A$

  • Select around a pair of separators.
  • Includes both separators and a surrounding whitespace, similar to a' and A(.
      ...........
a , b , cccccccc , d , e
      └─── A, ────┘

Next and Last Separator

in, an, In, An, il, al, Il, Al, ...

Work directly on distant separators without moving there separately.

All the above separator text objects can be shifted to the next separator by including the letter n. The command in, selects inside of the next commas. Use the letter l instead to work on the previous (last) separators. Uses the count to skip multiple separator characters.

See our Cheat Sheet for a chart summarizing all separator mappings.

Separator Seek

Like quote seeking. If any of the normal separator commands (not containing n or l) is executed when the cursor is not positioned inside a pair of separators, it seeks for the separator before or after the cursor. This is similar to using the explicit version containing n or l.

Argument Text Objects

These text objects are similar to separator text objects, but are specialized for arguments surrounded by braces and commas. They also take matching braces into account to capture only valid arguments.

Argument text objects work over multiple lines and support seeking.

In Argument

ia

  • Select inside arguments. Similar to in quote.
  • Accepts a count.
      ...........
a , b ( cccccccc , d ) e
       └── ia ──┘

An Argument

aa

  • Select an argument in a list of arguments.
  • Includes a separator if preset, but excludes surrounding braces. This leaves a proper argument list after deletion.
  • Accepts a count.
      ...........
a , b ( cccccccc , d ) e
        └─── aa ──┘

Inside Argument

Ia

  • Select content of an argument.
  • Like inside separators, but exclude whitespace at both ends. Useful for changing contents while preserving spacing.
  • Accepts a count.
      ...........
a , b ( cccccccc , d ) e
        └─ Ia ─┘

Around Argument

Aa

  • Select around an argument.
  • Includes both delimiters and a surrounding whitespace, similar to a' and A(.
  • Accepts a count.
      ...........
a , b ( cccccccc , d ) e
      └─── Aa ────┘

Next and Last Argument

ina ana Ina Ana ila ala Ila Ala

Work directly on distant arguments without moving there separately.

All the above argument text objects can be shifted to the next argument by including the letter n. The command ina selects inside of the next argument. Use the letter l instead to work on the previous (last) argument. Uses a [count] to skip multiple argument characters. The order is determined by the nearest surrounding argument delimiter.

See our Cheat Sheet for a chart summarizing all argument mappings.

Argument Seek

Like separator seeking. If any of the normal argument commands (not containing n or l) is executed when the cursor is not positioned inside an argument, it seeks for the argument before or after the cursor. This is similar to using the explicit version containing n or l.

Multi Text Objects

Two multi text objects are included in default settings. See the section on settings below to see how to set up other similar multi text objects or customize the built in ones.

Any Block

inb anb Inb Anb ilb alb Ilb Alb

Similar to pair text objects, if you type dib within () it will delete in these. If you do the same within {} it will delete in those. If you type d2inb it will skip one next pair (any kind) and delete in the one after (any kind). If you're within () nested in {}, type d2ib to delete in {}. All of the usual seeking, growing and skipping works.

Any Quote

inq anq Inq Anq ilq alq Ilq Alq

Similar to quote text objects, if you type diq within "" it will delete in these. If you do the same within '' it will delete in those. If you type d2inq it will skip one next quote text object (any kind) and delete in the one after (any kind). If you're within "" nested in '', type d2iq to delete in ''. All of the usual seeking, growing and skipping works.

Settings

You can customize the mappings and text objects with the settings described here.

g:targets_aiAI

Default:

let g:targets_aiAI = 'aiAI'

Controls the normal mode operator mode maps that get created for In Pair (i), A Pair (a), Inside Pair (I), and Around Pair (A). Required to be either a string or a list with 4 characters/elements.

Use a space to deactivate a mode. If you want to use multiple keys, for example <Space>a instead of A, you must use a list.

In contrast to g:targets_nl, special keys must not be escaped with a backslash. For example, use "<Space>" or '<Space>', not "\<Space>". Example for configuring g:targets_aiAI:

let g:targets_aiAI = ['<Space>a', '<Space>i', '<Space>A', '<Space>I']

g:targets_mapped_aiAI

Default:

let g:targets_mapped_aiAI = g:targets_aiAI

If you can't get your g:targets_aiAI settings to work because they conflict with other mappings you have, you might need to use g:targets_mapped_aiAI. For example if you want to map k to i and use k as i in targets mappings, you need to NOT map k to i in operator pending mode, and set g:targets_aiAI = 'akAI' and g:targets_mapped_aiAI = 'aiAI'.

Has the same format as g:targets_aiAI.

For more details see issue #213 and don't hesitate to comment there or open a new issue if you need assistance.

g:targets_nl

Default:

let g:targets_nl = 'nl'

Controls the keys used in maps for seeking next and last text objects. For example, if you want n to always search for the next object and N to search for the last, you could set:

let g:targets_nl = 'nN'

Required to be either a string or a list with 2 characters/elements.

Use a space to deactivate a mode. If you want to use multiple keys, for example <Space>n instead of n, you must use a list.

In contrast to g:targets_aiAI, special keys must be escaped with a backslash. For example, use "\<Space>", not "<Space>" nor '<Space>'. Example for configuring g:targets_nl:

let g:targets_nl = ["\<Space>n", "\<Space>l"]

g:targets_seekRanges

Default:

let g:targets_seekRanges = 'cc cr cb cB lc ac Ac lr rr ll lb ar ab lB Ar aB Ab AB rb al rB Al bb aa bB Aa BB AA'

Defines a priority ordered, space separated list of range types which can be used to customize seeking behavior.

The default setting generally prefers targets around the cursor, with one exception: If the target around the cursor is not contained in the current cursor line, but the next or last target are, then prefer those. Targets beginning or ending on the cursor are preferred over everything else.

Some other useful example settings:

Prefer multiline targets around cursor over distant targets within cursor line:

let g:targets_seekRanges = 'cc cr cb cB lc ac Ac lr lb ar ab lB Ar aB Ab AB rr ll rb al rB Al bb aa bB Aa BB AA'

Never seek backwards:

let g:targets_seekRanges = 'cc cr cb cB lc ac Ac lr rr lb ar ab lB Ar aB Ab AB rb rB bb bB BB'

Only seek if next/last targets touch current line:

let g:targets_seekRanges = 'cc cr cb cB lc ac Ac lr rr ll lb ar ab lB Ar aB Ab AB rb rB al Al'

Only consider targets fully visible on screen:

let g:targets_seekRanges = 'cc cr cb cB lc ac Ac lr lb ar ab rr rb bb ll al aa'

Only consider targets around cursor:

let g:targets_seekRanges = 'cc cr cb cB lc ac Ac lr lb ar ab lB Ar aB Ab AB'

Only consider targets fully contained in current line:

let g:targets_seekRanges = 'cc cr cb cB lc ac Ac lr rr ll'

If you want to build your own, or are just curious what those cryptic letters mean, check out the full documentation in our Cheat Sheet.

g:targets_jumpRanges

Default:

let g:targets_jumpRanges = 'bb bB BB aa Aa AA'

Defines an unordered, space separated list of range types which can be used to customize the jumplist behavior (see documentation on seek ranges). It controls whether or not to add the cursor position prior to selecting the text object to the jumplist.

The default setting adds the previous cursor position to the jumplist if the target that was operated on doesn't intersect the cursor line. That means it adds a jumplist entry if the target ends above the cursor line or starts below the cursor line.

Some other useful example settings (or build your own!):

Never add cursor position to jumplist:

let g:targets_jumpRanges = ''

Always add cursor position to jumplist:

let g:targets_jumpRanges = 'cr cb cB lc ac Ac lr rr ll lb ar ab lB Ar aB Ab AB rb al rB Al bb aa bB Aa BB AA'

Only add to jumplist if cursor was not inside the target:

let g:targets_jumpRanges = 'rr rb rB bb bB BB ll al Al aa Aa AA'

g:targets_gracious

Default:

let g:targets_gracious = 0

If enabled (set to 1) , both growing and seeking will work on the largest available count if a too large count is given. For example:

  • v100ab will select the most outer block around the cursor
  • v100inq will select the most distant quote to the right/down (the last one in the file)

targets#mappings#extend

This function can be used to modify an internal dictionary used to control the mappings. The default value of that dictionary is:

{
    \ '(': {'pair': [{'o': '(', 'c': ')'}]},
    \ ')': {'pair': [{'o': '(', 'c': ')'}]},
    \ '{': {'pair': [{'o': '{', 'c': '}'}]},
    \ '}': {'pair': [{'o': '{', 'c': '}'}]},
    \ 'B': {'pair': [{'o': '{', 'c': '}'}]},
    \ '[': {'pair': [{'o': '[', 'c': ']'}]},
    \ ']': {'pair': [{'o': '[', 'c': ']'}]},
    \ '<': {'pair': [{'o': '<', 'c': '>'}]},
    \ '>': {'pair': [{'o': '<', 'c': '>'}]},
    \ '"': {'quote': [{'d': '"'}]},
    \ "'": {'quote': [{'d': "'"}]},
    \ '`': {'quote': [{'d': '`'}]},
    \ ',': {'separator': [{'d': ','}]},
    \ '.': {'separator': [{'d': '.'}]},
    \ ';': {'separator': [{'d': ';'}]},
    \ ':': {'separator': [{'d': ':'}]},
    \ '+': {'separator': [{'d': '+'}]},
    \ '-': {'separator': [{'d': '-'}]},
    \ '=': {'separator': [{'d': '='}]},
    \ '~': {'separator': [{'d': '~'}]},
    \ '_': {'separator': [{'d': '_'}]},
    \ '*': {'separator': [{'d': '*'}]},
    \ '#': {'separator': [{'d': '#'}]},
    \ '/': {'separator': [{'d': '/'}]},
    \ '\': {'separator': [{'d': '\'}]},
    \ '|': {'separator': [{'d': '|'}]},
    \ '&': {'separator': [{'d': '&'}]},
    \ '$': {'separator': [{'d': '$'}]},
    \ 't': {'tag': [{}]},
    \ 'a': {'argument': [{'o': '[([]', 'c': '[])]', 's': ','}]},
    \ 'b': {'pair': [{'o':'(', 'c':')'}, {'o':'[', 'c':']'}, {'o':'{', 'c':'}'}]},
    \ 'q': {'quote': [{'d':"'"}, {'d':'"'}, {'d':'`'}]},
    \ }

The keys in this dictionary correspond to the trigger character. For example if you type di(, ( is the trigger and gets mapped to the pair target source with arguments 'o':'(' (opening) and 'c':')' (closing). Sources quote and separator have argument 'd' (delimiter), tag has no arguments and argument text objects take 'o' (opening), 'c' (closing) and 's' (separator). Notably the b (any block) and q (any quote) triggers map to one source with three sets of pair and quote argument dictionaries respectively. That means if you type dib each of those sources get taken into account to pick the proper target. Also note that it's even possible to have one target mapped to multiple different sources, so you can select any of those different text objects (see example below).

You can use the targets#mappings#extend() function to modify these internal mappings. For example if you wanted to switch b back to the Vim default behavior of operating on parentheses only, you can add this to your vimrc:

autocmd User targets#mappings#user call targets#mappings#extend({
    \ 'b': {'pair': [{'o':'(', 'c':')'}]}
    \ })

Note that you should always use that autocmd prefix to make sure your modifications get applied at the right time. There's a similar autogroup for plugins which can add other sources and default mappings, which gets triggered before this #user one. That way the user mappings always take precedence over the plugins default mappings

If you want to remove a mapping from the defaults, just set it to an empty list of sources:

autocmd User targets#mappings#user call targets#mappings#extend({
    \ 'q': {},
    \ })

That way targets.vim will ignore it and fall back to Vim default behavior, which for the case of q does nothing.

Finally here's a more complex example which adds two triggers s (any separator text object) and @ (anything at all). So you could type das to delete the closest separator text object near the cursor, or da@ to operate on the closest text object available via targets.vim. All of those support seeking and counts like d3ins.

autocmd User targets#mappings#user call targets#mappings#extend({
    \ 's': { 'separator': [{'d':','}, {'d':'.'}, {'d':';'}, {'d':':'}, {'d':'+'}, {'d':'-'},
    \                      {'d':'='}, {'d':'~'}, {'d':'_'}, {'d':'*'}, {'d':'#'}, {'d':'/'},
    \                      {'d':'\'}, {'d':'|'}, {'d':'&'}, {'d':'$'}] },
    \ '@': {
    \     'separator': [{'d':','}, {'d':'.'}, {'d':';'}, {'d':':'}, {'d':'+'}, {'d':'-'},
    \                   {'d':'='}, {'d':'~'}, {'d':'_'}, {'d':'*'}, {'d':'#'}, {'d':'/'},
    \                   {'d':'\'}, {'d':'|'}, {'d':'&'}, {'d':'$'}],
    \     'pair':      [{'o':'(', 'c':')'}, {'o':'[', 'c':']'}, {'o':'{', 'c':'}'}, {'o':'<', 'c':'>'}],
    \     'quote':     [{'d':"'"}, {'d':'"'}, {'d':'`'}],
    \     'tag':       [{}],
    \     },
    \ })

Also note how this example shows that you can set multiple triggers in a single targets#mappings#extend() call. To keep the autocmd overhead minimal I'd recommend to keep all your mappings setup in a single such call.

Deprecated settings

If you have set any of the following settings in your vimrc, they will still be respected when creating the default mappings dictionary. But it's not possible to set up any multi source targets (like any block or any quote) this way. It's recommended to retire those legacy settings and use targets#mappings#extend() as described above.

g:targets_pairs
g:targets_quotes
g:targets_separators
g:targets_tagTrigger
g:targets_argClosing
g:targets_argOpening
g:targets_argSeparator
g:targets_argTrigger

However, those new mappings settings will only be respected when targets.vim can use expression mappings, which need Neovim or Vim with version 7.3.338 or later. If you are using an older Vim version, these legacy settings are still the only way to do any customization. Please refer to an older version of this README (before October 2018) for details. Or open an issue for me to describe those legacy settings somewhere still.

Notes

Issues

Todos

Create more mappings to support commands like danw or danp to delete the next word or paragraph.

targets.vim's People

Contributors

airblade avatar alexis-d avatar balta2ar avatar bwhelm avatar casey avatar cenkalti avatar fxn avatar infokiller avatar jebaum avatar jsr-p avatar kba avatar lag13 avatar nedbat avatar peter50216 avatar romgrk avatar sandersantema avatar unrealquester avatar wellle avatar wilywampa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

targets.vim's Issues

redraw / flickering

Thanks for the plugin! It's really great.

When I enabled targets.vim and do a ci' for example the whole screen redraws. When I disable targets.vim this isn't the case anymore. It's only noticable when I edit .php files. I've tried python and css but they don't have this issue.

Make separator objects respect parentheses

https://asciinema.org/a/9101 - in which I thrash around trying to use these text objects without very much success

As far as I can pin down, separator objects don't respect their context very well. IE a comma-separated list extends through parentheses. I'd love to be able to "da," to delete a function parameter, but this doesn't work for the first or last right now.

If parentheses-respect were an option, that'd be OK, although it'd be nice if you could pick sane behaviour based on filetype.

Besides (), I'd also expect a comma list to end at [], {}, "", '', colon, semicolon and almost certainly others.

Deactivate Uppercase Versions I,A and N

How to selectively disable default bindings for the upper case versions of i,a + operator? The documentation says that all four bindings have to be set for every operator.

In particular

" add expression mappings for `A` and `I` in visual mode #23
function! s:addExpressionMappings()
    xnoremap <expr> <silent> A targets#uppercaseXmap('A')
    xnoremap <expr> <silent> I targets#uppercaseXmap('I')
endfunction

overrides other plugins' functions such as

https://github.com/kana/vim-niceblock

which prepends and appends text in a visual selection by I and A.

Option: Add to jumplist when seeking

I often encounter situations where I want to quickly change text in quotes or brackets (or any other delimiters), and then jump back to where I was before. For example, if the cursor is currently somewhere on the first line of the below, I may want to change the hello world text, then go back to whatever I was doing back on the first line.

int c = 0;
c++;
int x = 2 * c;
string s = "hello world";

It would be nice if this was possible by just hitting <C-o>, and I think it would be handy if targets.vim had the option of adding the current location to the jumplist before seeking to a text object.

Last pair mappings do not seem to work.

Great plugin! Sadly, none of the last pair mappings seem to work for me.

Here are some examples of the behavior I am seeing. Assume an otherwise empty buffer for each example, with the cursor located at line 1, column 1. The first line is the only text inside the buffer. The second line is the normal mode command I entered. The third line is my expected result. The fourth line is the actual result.

('one', 'two', 'three')
dil'
('one', 'two', '')
('one', two', 'three')


(one) (two) (three)
dil(
(one) (two) ()
(one) (two) (three)

Any thoughts?

g:targets_aiAI and g:targets_nlNL are broken

After updating targets, I got a ton of messed up mappings because the parts of g:targets_aiAI and g:targets_nlNL I replaced with spaces now get mapped, e.g.

silent! execute 'onoremap <silent> <unique>' . s:A . s:L . triggerMap . "LA')<CR>"

executes

onoremap <silent> <unique>  % :<C-U>call targets#o('%LA')<CR>

so now % by itself is mapped to call targets#o('%LA').

normal map `P` broken

Let * = cursor position.

Found:

*hello

Then hitting yiwP gives

hello*o

Expected:

hello*hello

Make "a quote" be "Around quote" and add real "a quote" that ignores whitespace

Is there a reason you've made a for quotes behave more like A for everything else? I'd really love to have a for quotes where it doesn't select whitespace.

Basically make it so the chart for a list of quotes from the cheatsheet looks like this:

                    ..........
a ' bbbbbbb ' ccccccc ' dddddd ' eeeeeee ' fffffff ' g
  ││└ IL' ┘│││└ Il' ┘│││└ I' ┘│││└ In' ┘│││└ IN' ┘│││
  │└─ iL' ─┘│└─ il' ─┘│└─ i' ─┘│└─ in' ─┘│└─ iN' ─┘││
  ├── aL' ──┼── al' ──┼── a' ──┼── an' ──┼── aN' ──┘│
  └── AL' ──┼┘        └┼─ A' ──┼┘        └┼─ AN' ───┘
            └── Al' ───┘       └── An' ───┘

I think I can see how to add it myself (from an admittedly brief look through s:createQuoteTextObjects()), but based on how easy it would be for me to add, it makes me think you've made this a deliberate choice.

At the very least, I can see that adding this would make the plugin work differently for most of its existing users. But seems like the consistency across the different objects would make the change worthwhile. Maybe there could be some sort of option to get the old behavior.

Would you accept any patches related to this?

ci" doesn't repeat correctly

Using Vim 7.2 and targets.vim commit #401b1b9, if I change the text inside double quote marks using ci" and then try this again inside another pair of double quotes using ., it replaces the wrong text unless (a) the text is the same length, and (b) the cursor is in the same place within the text.

Argument Text Object Count Unappreciated

Given call foo("bar", "baz", "bla", "robot") and any argument text input with counts such as v2aa, c3ia, the cursor is repositioned to the start-of-line and no object is modified by the operator.

Vim < 7.3: "Unknown function: undotree"

I'm running Vim 7.2, and as such, when I attempt an invalid targets.vim action, I get the following error (since Vim < 7.3 doesn't have undotree):

Error detected while processing function targets#match..targets#handleMatch..targets#abortMatch:
line    5:
E117: Unknown function: undotree
E15: Invalid expression: undotree().seq_cur
line    6:
E121: Undefined variable: undoseq
E116: Invalid arguments for function feedkeys

Bug while changing inside angle-braces

This is my code

nnoremap <A-f> [I:let nr = input("Find: ")<Bar>exe "normal " . nr ."[\<C-I>"<CR>

My cursor is on the dash in <C-I>. If I type di<, the line changes to

nnoremap <A-f> [I:let nr = input("Find: ")<Bar>exe "normal " . nr ."[\<C-I>"<>

instead of

nnoremap <A-f> [I:let nr = input("Find: ")<Bar>exe "normal " . nr ."[\<>"<CR>

as expected.

omap command line clearing breaks ys from surround

Almost immediately, I noticed that I was getting weird behavior from this plugin when using some surround commands. For instance:

(asdf)
  ^ caret

ysi) would immediately put a colon in front of the a. It turns out this is caused by targets#omap doing extra cleanup. ys expects additional input after the text object, much like c, so the check in s:clearCommandLine should test for 'g@' as well. Unfortunately, that's about the best that can be done (I think), even though other custom operators may not expect more input.

make targets.vim more robust by avoiding i and a mapping in visual and operator mode

Hello, targets would be less intrusive if it could avoid overwriting i and o in visual and operator mode.

For example, even if target is not used, such as for iw in operator mode, it caused a bug in #92

Another point is that the check

" [rectangle]
onoremap <unique> ar  a]
xnoremap <unique> ar  a]
onoremap <unique> ir  i]
xnoremap <unique> ir  i]

if ir/ar is already mapped in operator/visual mode does not work, because targets overwrites i and a.

Argument Text Object: Handle quotes

Let's select an argument with visual-mode operator!

Problem 1

Expected:

                  +
function(a, 33, Rstyle="calls, with commas inside strings, are OK")
              +--------------------------------------------------+

Actual:

                  +
function(a, 33, Rstyle="calls, with commas inside strings, are OK")
              +-------------+

Whereas this works as expected:

               +
function(a, 33, [1, 2, 3, 4, 5, ], 61234, V="one, two", )
              +-----------------+

Conclusion: the argument text object is smart enough to ignore nested argument objects, but not smart enough to ignore pair-text-objects and quote-text-objects as arguments.

Problem 2

Expected:

                                    +
function(a, 33, Rstyle="calls, with commas inside strings, are OK")
              +--------------------------------------------------+

Actual

                                    +
function(a, 33, Rstyle="calls, with commas inside strings, are OK")
                             +--------------------------+

Perhaps a nesting bug, so I repeat the text object in visual-mode (the previous range is above, the final below):

                                    +
                             +--------------------------+
function(a, 33, Rstyle="calls, with commas inside strings, are OK")
+

Conclusion: this is just plain broken.

Growing with a* doesn't work.

One of my common use cases with "around" objects is to grow a selection several times, e.g. to see the extents of a structure in a JSON file, and then its containing structures. In this example, starting anywhere in the dots on the cursor line, I should be able to vaB to select the inner {} structure, and then aB to grow to the outer one directly from there.

cursor          ............
sample {"foo": {"bar": "baz"}}
vaB            └────────────┘
aB     └─────────────────────┘

However, this does not currently work against tag v0.1.2.

Plugin is slow to load

In my configuration, targets takes around 115ms to load, which I consider unacceptable for a single plugin.

Is there a way to iterate faster so that the load time is not so long?

Cheers!

Separator Text Object: Should Support Count and Ignore Quote/Pair Text Objects

Expected:

v2in.
       +
"a" . "b" . "c" . "dd . ee . ff" . "c" . "b" . "a"
                 ++++++++++++++++

With behaviour similar to that of pairs text objects:

v3in.
       +
"a" . "b" . "c" . "dd . ee . ff" . "c" . "b" . "a"
                 +++++

Be extension, [count] would break out of separator objects nested in quotes or pairs:

v2i.
                        +
"a" . "b" . "c" . "dd . ee . ff" . "c" . "b" . "a"
                 ++++++++++++++++

Use silent! execute and <unique> to create non-clobbering mappings?

Hi, I started using vim-textobj-line again and I realized that its mappings conflict with that of this plugin. Since, I've been using n/l for next/last for quite some time now, I changed textobj-line's mappings to use _ since _ kind of represents a line-textobj. However, this still conflicts with targets.vim

Would it be possible to use :silent! execute and <unique> while creating the maps so that any user-defined mappings are not overwritten?

I was also reading your response here and was intrigued by the idea of using n/N instead of n/l. Is this something that you have tried or plan on supporting? If not, I'll just hack it in my work-area and see how it feels.

Thanks for an awesome plugin :) 👍

vI<text object> and vA<text object> broken

It seems that while in visual mode, when pressing I or A it immediately performs the action as if it were in normal mode (aka going to the beginning of the line and going into insert mode)

This only happens in visual mode.

vI<text object> and vA<text object>

performed my tests on:
( foobar )
' foobar '
( foobar ) .
' foobar ' .

Possible bug about when to seek for tags

I'm still wrapping my head around the seeking in targets.vim, so help me out here. If I have the following bit of code in file...

<div>
    <span>A</span>
</div>

And my cursor is at the beginning of the middle line, and I type vit, it seems to me that it should select the entire middle line, and not just A. Can you reproduce this? Is this the correct behavior?

Lag when inserting before of after a block selection

There is a noticeable lag that this plugin introduces when inserting before or after a block selection.

To reproduce create a file like this:

asdf=
asdf=
asdf=

Visually select all the = signs, execute shift+A. There is a noticeable lag before it drops you into insert mode.

Is there any possibility of reducing or eliminating this lag?

Indenting inside curly braces includes last brace line

First of all, thank you for the fantastic work on this plugin! I've been trying to cib from the start of an if () line for ages like you can with ci" and now I finally can!

Here's my bug report. In the context of:

    if (foo) {
    bar += 1;
    }

with the cursor on bar, executing >iB results in:

    if (foo) {
        bar += 1;
        }
//      ^-- wrong

where it should be:

    if (foo) {
        bar += 1;
    }
//  ^-- right 

I don't really use the seeking with curly braces so I've just disabled it for now, but thought you'd like to know :)

Option: Add to jumplist if movement spans certain number of columns

Would you accept a patch that adds the old cursor position to the jumplist if the object is on the same line, but some configurable number of columns away from the cursor? E.g:

int some_int = x + y + this_is_a_long_function_name_that_spans_lots_of_columns(x, y);

If the cursor is on the s in some, and you do ci(, you may want to hop right back to where you were. Personally I run into this situation frequently enough that I think this would be useful.

Alternatively, you could have an option to always add to the jumplist no matter what. The upside of this would be extremely simple code, the downside is cluttering the jumplist with some unnecessary entries. I would rather have a bit of clutter on the jumplist than have something not be on it that I wish was there, but obviously that's personal taste.

If you're willing to go this simpler route, I threw together a quick patch:

diff --git i/autoload/targets.vim w/autoload/targets.vim
index 699b7fe..82a4eb7 100644
--- i/autoload/targets.vim
+++ w/autoload/targets.vim
@@ -119,7 +119,7 @@ endfunction
 function! s:selectMatch()
     " if the match starts below the current line or ends above the current
     " line (the cursor is not linewise inside the match)
-    if s:oldpos[1] < s:sl || s:oldpos[1] > s:el
+    if s:oldpos[1] < s:sl || s:oldpos[1] > s:el || exists('g:targets_jumplist_always')
         call setpos('.', s:oldpos) " move cursor to old position
         execute "normal! m'" |     " and add it to the jump list
     endif
diff --git i/doc/targets.txt w/doc/targets.txt
index 8ffb64b..65fb213 100644
--- i/doc/targets.txt
+++ w/doc/targets.txt
@@ -389,6 +389,7 @@ Available options: ~
     |g:targets_pairs|
     |g:targets_quotes|
     |g:targets_separators|
+    |g:targets_jumplist_always|

 ------------------------------------------------------------------------------
                                                               *g:targets_aiAI*
@@ -445,6 +446,14 @@ letter alias. To set 'c' as an alias for comma, allowing such commands as

     let g:targets_separators = ',c . ; : + - ~ _ * / \ |' ~

+                                                    *g:targets_jumplist_always*
+Default:
+    not defined by default ~
+
+If defined, always add current cursor position to jumplist before performing a
+text object motion. The default behavior is to only add to the jumplist if the
+object starts below or ends above the current line.
+
 ==============================================================================
 NOTES                                                          *targets-notes*

Request: Add support for multiline quotes

Vim, by default, doesn't treat multiline strings similar to multiline braces. For eg. in case of

"Some text |here
and more text here"

where | denotes the position of the cursor. Pressing di" doesn't delete the entire string.

Would it be possible to treat ', " and ` similar to braces in this regard?

targets.txt contains error

Line 296 in targets.txt causes vim to issue the following error when generating help tags:

E154: Duplcate tag "A&" in file targets.txt

The line in question contains:

I~ I_ I* I/ I| I\ A&                     *I~* *I_* *I/* *I|* *I\* *A&* *Istar*

I believe those instances of "A&" should be "I&"

Non-intuitive behavior with line seeking in certain edge cases.

I noticed this first in my .vimrc because I have some fun bindings in there and apparently they make the plugin act funny... Minimal working example here, X being cursor position.

let g = {
     \ { arg 1 },
    X\ { arg 2 },
}

If you type the command ci{, the resulting output should (intuitively) erase "arg 2" and leave you in the appropriate spot in insert mode. The current behavior ends up with

let g = {
X
}

However cin{ works fine, and cil{ performs on the curly braces surrounding "arg 1" as expected.

The second bug is similar.

X beautifulCode text [ things ] ; 
...
(50 lines down the vimrc later)
...
noremap p ]p

Typing ci[ from the cursor position erases EVERYTHING in-between the first bracket and the one at the last line, leaving the result:

beautifulCode text [X]p

Typing cin[ works properly, however. Additionally, it's also worth noting that vim's built in % matching command seems to automatically match the first line with the "matching" bracket 50 lines down, just like your plugin does.

It seems to me that, intuitively, the plugin should automatically seek within the line first, and then +/-1, before going to the "largest area currently within". However, that does raise the question of how you would operate on the entire surrounding curly brace (e.g. in example 1) if the plugin defaulted to line search, so perhaps a proximity setting might be in order? If I'm within, say, 10-15 characters of something more narrow that matches the command, then act on that instead of the wider selection, and if I'm further away from it (say, at the other end of a line of code), the plugin should act on the larger area.

An example:

let g = {
    [X]more text, and other fancy things, probablyLongEnoughToBeAJava[Y]NameNow { arg },
}

If the cursor was at, say, the position of [X], then ci{ would act on the curly braces surrounding the entire line, whereas if it was at the position [Y], ci{ would act on the braces surrounding "arg".

One last issue. If I have some text like:

X  ..... 
(30 lines down)
<foo> things

And I press ci<, the cursor will jump all 30 lines down and give the result <X>. This is cool, but I don't know if having the text searching being unlimited is really a good idea, I imagine it would be horribly frustrating to hit the wrong key and accidentally end up somewhere 200 lines over, in a larger codebase. Perhaps a vertical limit of, say, ~15 lines would be more appropriate? Of course this and the line-wise priority could be adjustable/able to be turned off by the end user, or whatever.

Sorry for the wall of text. Also not quite sure whether to call this a bug or "thang1thang2 is weird and likes weird things and makes weird suggestions"...

[RFC] Add mappings for first and last text objects in current line?

Inspired by #80.

It could be useful to have mappings like

  • ciF" to change inside the first quotes in the current line
  • ciL" to change inside the last quotes in the current line

This should not be confused with the current word last meaning previous.

I think the current L and N mappings are not really useful, so I think we could use F and L for this.

Any comments?

Add documentation for argument customization

could you add such argument for C language:

for (i = 0; i < 10; i++)

cia / caa can change i = 0 or i = 0;

I mean ia / aa can select argument between ; just for for loop of C .

Thanks

Duplicate helptags for `Ia`, etc.

For a bunch of the operators, there’s a tag for the summary, and then for the detailed help for that specific operator. e.g. Ia is tagged on both line 100 and 436. This upsets :helptags a bit: :h Ia still jumps to its help on line 100, but making the tags in the first place gives some errors.

(I didn’t fix it myself and do a pull request since I’m not sure which one to change and what to call it…)

When target doesn't exist, no error, and command is put into undo history

Say I have this line, because I just installed targets.vim and am playing:

asdf;asdf;asdf;asdf;asdf;asdf;asdf;asdf;asdf;asdf;asdf

With my cursor somewhere in that line, I start typing da; over and over again until I end up with this:

asdf;asdf

Pressing da; again doesn't do anything, of course, because there is only one semicolon left. But there is no error, and the command is entered into the undo history. For instance, if at this point I (ineffectively) hit da; three times, I have to hit u three times to "actually start undoing" and get my text back to where it was before the last successful da;.

# (ci#, etc) mappings don't seem to be firing unless g:targets_separators is specified

I was having an issue changing inside # separators, for example changing 'that' in thing#that#does#stuffI would put my cursor inside the word 'that' and press ci# expecting to be left in insert mode with thing##does#stuff. sadly this action doesn't seem to work (nor does any other map containing a #)

The plugin in seems to be running fine, calling `:exe 'norm ci#' in the same situation seems to work as expected.

On my keyboard # is fired by pressing ⌥+3 (equivalent of ALT+3). there might be an escape char issue?

setting let g:targets_separators = ', . ; : + - = ~ _ * # / | \ & $' from either Ex or my vimrc seems to fix the issue but loading the plugin without with this setting behaves as above.

This solution works for me, but there might be an issue somewhere.

Argument Text Object: Error if Count Too Large

" -- cursor -------|
call foo("bar", "baz", foo("bar", "baz", "bla", "robot"), "bla", "robot") 

with

v2aa

causes

E117: Unknown function: getcmdwintype                                                          
E15: Invalid expression: getcmdwintype() ==# ""                                                
Error detected while processing function targets#x..<SNR>106_abortMatch:    
line    2:    

on vim 7.4.273

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.