Editor that will jump to a given character based on position from EOF? - vim

Anybody know of an editor with a command that will jump your cursor to a given byte/character based on it's position to the end of the file (EOF) instead of the beginning of the file?
Something tells me that VI/VIM can do it but my Google-fu is failing me at the moment.

(defun go-to-nth-from-eob (n)
"Go to the Nth character from the end of the buffer.
Interactively, N is the numeric prefix argument."
(interactive "p")
(goto-char (- (point-max) n))))

Emacs can do this.
To move to the nth character in the file, you can use goto-char. So if you want to go to the 1234th character, run M-x goto-char, and in the following prompt, you can type 1234.
But it doesn't work for going to the nth character from the end. Luckily, we can write a method!
(defun goto-char-from-end (characters-from-end)
"Goes to the end of the buffer, then steps characters-from-end characters back."
(interactive "Nhow many characters back? ")
(end-of-buffer)
(backward-char characters-from-end))
This can be used the same way, with M-x goto-char-from-end. Also like goto-char, you can use prefix arguments: type C-1 C-2 M-x goto-char-from-end, and it will go to the twelfth character from the end without prompting you.
To load this code into Emacs, copy it into a buffer, then put your cursor after the last parenthesis, and type C-x C-e. That runs the code, and puts the function in the currently-running Emacs. If you like it and want to have it forever, the way to do that is to put it in your init file.

The following Vim mapping will make [count]gO behave like [count]go, but backwards from EOF:
nnoremap <silent> gO :<C-u>execute "normal!" (line2byte(line('$') + 1) - 1 - v:count) . "go"<CR>
line2byte(line('$') + 1) - 1 is the number of bytes in the buffer, and v:count is the given [count] (defaults to 0, so gO is equivalent to G$).

Vim
Lets say you want to go to the 13th character from the end of the file. Press:
G$13<C-h>
Details:
G$ - go to last character in the buffer
13<C-h> - go left 13 characters, going over line breaks (<C-h> is Ctrl+h)
Instead of the <C-h> key you can also use <left> if you've enabled it with the whichwrap setting.

One alternative with Emacs is to advise goto-char so that it interprets negative arguments in a natural way:
(defadvice goto-char (before interpret-negative-argument activate)
(when (and (called-interactively-p)
(> 0 (ad-get-arg 0)))
(ad-set-arg 0 (+ 1 (buffer-size) (ad-get-arg 0)))))
Now you do eg. C-u-10M-gc to jump to the tenth character from the end.
Note that I've used buffer-size rather than point-max to mirror the way goto-char usually works with narrowing.

Related

Writing whole alphabet in Vim

I sometimes need to write the whole alphabet abcd…z and I hate typing it letter by letter in Vim's insert mode. Does there exist any method to do this more efficiently?
I know about the ga command which gives me the ascii code of the character where the cursor is … but don't know anything about how to mix it with my standard solution to type numbers from 1 to (for example) 5000: a1ESCqqyyp^Aq4998#q …
Using set nrformats+=alpha:
ia<Esc>qqylp<C-a>q24#q
Step by step:
ia<Esc> " Start with 'a'
qqylp<C-a>q " #q will duplicate the last character and increment it
24#q " Append c..z
If your shell does brace expansion this is a pretty elegant solution:
:r !printf '\%s' {a..z}
:read! reads the output of an external command into the current buffer. In this case, it reads the output of the shell's printf applied to {a..z} after it's been expanded by the shell.
How about this command:
:put =join(map(range(char2nr('a'),char2nr('z')),'nr2char(v:val)'),'')
Collect the ASCII values of the characters in the range from a to z, then map them over the nr2char() function and insert the result into the current buffer with :put =.
When you leave out the enclosing join( … ,'') you get the characters on a separate line each.
See
:h nr2char(),
:h char2nr(),
:h :put,
and look up range(), map(), join() and friends in the list-functions table.
First, set nrformats+=alpha.
Then:
ia<ESC>Y25p<CTRL-V>}g<CTRL-A>k26gJ
Which means:
ia insert the initial a
Y25p yank the a and duplicate it on 25 lines
<CTRL-V> go into visual block mode
} go to the last character at the end of the current paragraph
g<CTRL-A> incrementally increase each alphabetic character (see help v_g_CTRL-A)
k go up one line
26gJ join 26 lines without inserting or removing any spaces
Which leads to:
abcdefghijklmnopqrstuvwxyz
I have found a shorter solution (you don't need to change nrformats beforehand) while solving http://www.vimgolf.com/challenges/5ebe8a63d8085e000c2f5bd5
iabcdefghijklm<Esc>yiwg??P
which means:
iabcdefghijklm<Esc> insert first half of the alphabet
yiw copy it
g?? ROT13 encode (shift by 13 letters) to get the second half
P paste the first half
You might try using Vim abbreviations or a full-fledged snippet manager plugin like UltiSnips. It might take a few moments to set up, and you'd have to type that alphabet one more time to define it as an abbreviation or snippet, but after that you'd be able to insert the alphabet or any other common chunk of text much more easily.

Using Vim, isn't there a more efficient way to format LaTeX paragraphs according to this best practice?

The best practice mentioned in the title is the one suggested by Uri:
When writing paragraphs, start each
sentence at the beginning of a line,
and if it spills over, each subsequent
line is tabbed.
I use gVim with Vim-LaTeX, which comes with an indent/tex.vim file, to edit LaTeX files. The way I currently implement the practice mentioned above is as follows:
I :set textwidth=79 to automatically break lines before they become too long.
I manually hit Enter after I finish inserting each sentence.
If I'm done with revising and editing a sentence, I manually shift any spillovers using >>, prefixing it with a count if necessary.
Occasionally, that last step will make one or more spillovers go over the maximum line width. In this case, I
gqq the faulty line.
J my way through to the end of the sentence.
repeat steps 1 and 2 as necessary.
As you can imagine, this can become tedious. Isn't there a more efficient way to achieve the same result? Ultimately, I want to be able to write the sentences without worrying about their format, and then use gqap, or gqip, to automatically produce the result that I currently produce manually.
To do that, I suspect that I will need to write a formatexpr of my own, but I'm not sure how to proceed. I have found a number of plugins, Latex Text Formatter and Text (Especially LaTeX) Formatter, and a tip, but none of them seem to suit my needs, and I'm not sure how to modify them to do so.
I may well be oversimplifying the problem, but does this mapping do what you want?
nnoremap \z (j>>gq)
So pressing \z in normal mode will do the following: From the cursor position, jump to the start of the sentence. Then go to the next line and indent it. Then reformat from this line to the end of the sentence. Reformatting sentence-wise is the way to go, rather than reformatting each line individually, as your method seems to do.
Of course you can use an insert-mode mapping if you prefer, or even try redefining the behaviour of the Enter key to do this automatically (although I don't know if this will have unintended consequences...).
One way to do this is not by actually breaking the lines in the file but instead doing the following:
set wrap linebreak
let &showbreak='===> '
The wrap option makes long lines wrap instead of extending off the screen and linebreak makes the line breaks happen only at characters specified in the breakat option.
You can set showbreak to anything that is pleasing to your eye. My favorite when I'm using vim where unicode characters work right is:
let &showbreak="\u21aa "
This puts a ↪ symbol at the beginning of each wrapped line.
I also like to turn on line numbers (set number) to give another indicator of what the actual lines in the file are.
To make navigating the file easier you might want to use
noremap j gj
noremap k gk
noremap gj j
noremap gk k
This makes k and j move up and down by displayed lines not file lines. To affect the cursor keys as well replace k with <Up> and j with <Down>.
One option that takes different tack than tabbing subsequent lines would be to set the w flag in formatoptions. When you do that it changes the way Vim identifies new paragraphs, and lines ending in a space are understood to continue on a new line as part of same paragraph. See :h fo-table.
If you set the w flag and enter your text so that continued sentence lines are the only ones ending in a space (and abandon completely practice of entering tabs at beginning of any text lines) then I think you should be able to use gqap to format text paragraphs as you want. To get visual cues to logical structure you can then set listchars to display the eol (i.e., <cr>) character and set different highlightings for <space><cr> and for <non-space><cr> so that sentence/paragraph ends are easily spotted.
Another benefit of this method is that you can just type your text naturally and let line breaks be entered automatically by textwidth setting. (Just make sure that LaTeX formatting lines don't break automatically in textwidth area; you want them to have non-space char as last char in line.)
That tip also caught my eye. Here's how I solved the problem (a diff of the changed lines in tex.vim):
*** tex.vim.old 2011-08-16 08:26:56.845046457 +0200
--- tex.vim 2011-08-16 08:59:14.736306930 +0200
***************
*** 90,95 ****
--- 90,96 ----
" LH modification : \begin does not always start a line
if line =~ '\\begin{\(.*\)}' && line !~ 'verbatim'
\ && line !~ 'document'
+ \ || line =~ '^\s*[A-Z].*[a-zA-Z0-9,]\s*$\C'
let ind = ind + &sw
***************
*** 105,110 ****
--- 106,112 ----
" Subtract a 'shiftwidth' when an environment ends
if cline =~ '^\s*\\end' && cline !~ 'verbatim'
\&& cline !~ 'document'
+ \|| line =~ '\.\s*$'
if g:tex_indent_items == 1
" Remove another sw for item-environments
Basically it indents new lines when the previous line starts with a capital letter and ends with a letter, digit, or comma, and "unindents" new lines with the previous line ends with a period.
There is definitely room for improvement (better criteria) but for me it works all right so far.
I find the suggestion from #kev (and the people commented) at this post to be the most satisfying.
There, it is explained that by setting
:set fo+=n
followed by either
:let &flp='^\s*\\(item\|end\|begin)*\s*'
or
:let &l:flp='^\s*\\\(item\|end\|begin\)\s*'
lets you type gggqG to reformat the entire file.
I use the vim-textobj-usr plugin to define a "LaTeXPar" text-object. Then I can use gwal to format.
There is already a vim-textobj-latex plugin, but the biggest text-object it defines is "environment". This is not what I (and OP) want.
A "LaTeXPar" is delimited by
an empty line
a line begin with \[, \], \begin, \end, }
a line end with {
this is adapted to my writing habit: I always have an empty line after \section, always use \[ \] on a single line, and so on. You can easily write one for yourself.
Here is the relative part in my ~/.vim/ftplugin/tex.vim.
call textobj#user#plugin('latexpar', {
\ 'par': {
\ 'select-a-function': 'LaTeXPar',
\ 'select-a': 'al',
\ },
\ })
function! LaTeXPar()
let pattern='\v^$|^\s*(\\\[|\\\]|\\begin|\\end|\})|\{$'
if search(pattern,"bW")
normal! j
else
normal! gg
endif
let head_pos = getpos('.')
if search(pattern,"W")
normal! k
else
normal! G
endif
let tail_pos = getpos('.')
" echo head_pos[2]
" echo tail_pos[2]
return ["V", head_pos, tail_pos]
endfunction

Prepending a character followed by the line number to every line

I'm hand-editing CNC Gcode text files and need a way to reference locations in the file and on the toolpath.
I want to modify every line in the text file so that it begins with the the upper case letter N followed by the line number, incremented in tens for each successive line, then a whitespace followed by the original text on that line. How can I do this in Vim?
I'm not sure about vi, but (since you're using the vim tag) Vim allows you to accomplish your task as follows:
Adjust the first line by hand (insert a N10 at the beginning of the line), then put the cursor at the beginning of the next line.
Press qb to start recording a macro (the b names the register used to store the macro; feel free to use a different letter -- and definitely do use a different letter if you've got something useful stashed away in b).
Move the cursor upward to the beginning of the previous line (which you have adjusted by hand). Press v to start visual selection mode, then f to move the cursor to the next space on the line (if you use a single space as your whitespace separator, that is; adjust this step if you're using a tab or multiple spaces).
Press y to yank the selected text. This will also remove the visual selection.
Move the cursor to the beginning of the next line. Press P to insert the previously yanked text before the cursor, that is, on the very beginning of the line.
Move the cursor to the numeric part of the line header. Press 10 C-a (1, 0, control + A) to increment that number by 10.
Move the cursor to the beginning of the next line. Press q to stop recording the macro.
Press 10000000 #b to execute the macro 10000000 times or until it hits the end of the file. This should be enough to take care of all the lines in your file, unless it is really huge, in which case use a bigger number.
...or use Vim to write a simple script to do the job in whichever language you like best, then run it from a terminal (or from withing Vim with something like :!./your-script-name). ;-)
The following command will prepend ‘N<line number * 10>’ to every line:
:g/^/exe 'normal! 0iN' . (line('.')*10) . ' '
You can do it easily in Vim with this:
:%s/^/\=line(".")*10 . " "/
This replaces the start of every line with the result of an expression that gives the line number times ten, followed by a space.
I have not timed it, but I suspect it might be noticeably faster than the other Vim solutions.
Cheating answer:
:%!awk '{print "N" NR "0", $0}'
There are two ways to implement that without resorting to external
tools: via a macro or by using Vimscript. In my opinion, the first way
is a little cumbersome (and probably not as effective as the solution
listed below).
The second way can be implemented like this (put the code into your
.vimrc or source it some other way):
function! NumberLines(format) range
let lfmt = (empty(a:format) ? 'N%04d' : a:format[0]) . ' %s'
for lnum in range(a:firstline, a:lastline)
call setline(lnum, printf(lfmt, lnum, getline(lnum)))
endfor
endfunction
The NumberLines function enumerates all lines of the file in a given
range and prepends to each line its number according to the provided
printf-format (N%04d, by default).
To simplify the usage of this function, it is convenient to create
a command that accepting a range of lines to process (the whole file,
by default) and a optional argument for the line number format:
command! -range=% -nargs=? NumberLines <line1>,<line2>call NumberLines([<f-args>])

How do I emulate Vim's 'softtabstop' in Emacs?

I've been trying to get into emacs lately, and one of the things I need to get right is indentation.
Example 1:
sub foo {
my $bar = 'quux';
|
Example 2:
sub foo {
my $bar = 'quux'; |# foo
Imagine that the pipe character in the above examples indicates the cursor position. Now, I use (4) spaces for every indent level (no tabs), and I have emacs setup to indent my code automatically with that in mind. No problems there. But in the examples above, if I were to hit backspace at the indicated cursor positions, I want emacs to backspace all the way back to the next indent level (column / 4). That is, I want it to treat the preceding whitespace as if it were made up of tabs. Instead, it always just erases a single space character.
In vim, I turn on 'expandtab' to make it insert spaces instead of tabs, and 'softtabstop', which makes it (among other things) backspace to the next "soft tabstop" as described above.
In emacs, I suppose I could (if I knew emacs/elisp better) bind backspace to a function which does something like the following:
if indent-tabs-mode is nil
if the cursor position is preceded by whitespace
calculate the position of the previous "soft tabstop"
if there's enough whitespace
backspace all the way to that point
else
backspace by one character
What I want to know is, is there a simpler way to do this, and/or does anyone know of an existing solution?
This works for me, where the 'tab-width is used as the width of the columns. Set the key in the appropriate keymaps...
(local-set-key (kbd "DEL") 'backward-delete-whitespace-to-column)
(defun backward-delete-whitespace-to-column ()
"delete back to the previous column of whitespace, or as much whitespace as possible,
or just one char if that's not possible"
(interactive)
(if indent-tabs-mode
(call-interactively 'backward-delete-char-untabify)
(let ((movement (% (current-column) tab-width))
(p (point)))
(when (= movement 0) (setq movement tab-width))
(save-match-data
(if (string-match "\\w*\\(\\s-+\\)$" (buffer-substring-no-properties (- p movement) p))
(backward-delete-char-untabify (- (match-end 1) (match-beginning 1)))
(call-interactively 'backward-delete-char-untabify))))))

How do I move to end of line in Vim?

I know how to generally move around in command mode, specifically, jumping to lines, etc. But what is the command to jump to the end of the line that I am currently on?
Just the $ (dollar sign) key. You can use A to move to the end of the line and switch to editing mode (Append). To jump to the last non-blank character, you can press g then _ keys.
The opposite of A is I (Insert mode at beginning of line), as an aside. Pressing just the ^ will place your cursor at the first non-white-space character of the line.
As lots of people have said:
$ gets you to the end of the line
but also:
^ or _ gets you to the first non-whitespace character in the line, and
0 (zero) gets you to the beginning of the line incl. whitespace
$ moves to the last character on the line.
g _ goes to the last non-whitespace character.
g $ goes to the end of the screen line (when a buffer line is wrapped across multiple screen lines)
The main question - end of line
$ goes to the end of line, remains in command mode
A goes to the end of line, switches to insert mode
Conversely - start of line (technically the first non-whitespace character)
^ goes to the start of line, remains in command mode
I (uppercase i) goes to the start of line, switches to insert mode
Further - start of line (technically the first column irrespective of whitespace)
0 (zero) goes to the start of line, remains in command mode
0i (zero followed by lowercase i) goes the start of line, switches to insert mode
For those starting to learn vi, here is a good introduction to vi by listing side by side vi commands to typical Windows GUI Editor cursor movement and shortcut keys.
vi editor for Windows users
If your current line wraps around the visible screen onto the next line, you can use g$ to get to the end of the screen line.
I can't see hotkey for macbook for use vim in standard terminal. Hope it will help someone.
For macOS users (tested on macbook pro 2018):
fn + ← - move to beginning line
fn + → - move to end line
fn + ↑ - move page up
fn + ↓ - move page down
fn + g - move the cursor to the beginning of the document
fn + shift + g - move the cursor to the end of the document
For the last two commands sometime needs to tap twice.
The dollar sign: $
Press A to enter edit mode starting at the end of the line.
The advantage of the 'End' key is it works in both normal and insert modes.
'$' works in normal/command mode only but it also works in the classic vi editor (good to know when vim is not available).
Also note the distinction between line (or perhaps physical line) and screen line. A line is terminated by the End Of Line character ("\n"). A screen line is whatever happens to be shown as one row of characters in your terminal or in your screen. The two come apart if you have physical lines longer than the screen width, which is very common when writing emails and such.
The distinction shows up in the end-of-line commands as well.
$ and 0 move to the end or beginning of the physical line or paragraph, respectively:
g$ and g0 move to the end or beginning of the screen line or paragraph, respectively.
If you always prefer the latter behavior, you can remap the keys like this:
:noremap 0 g0
:noremap $ g$
In many cases, when we are inside a string we are enclosed by a double quote, or while writing a statement we don't want to press escape and go to end of that line with arrow key and press the semicolon(;) just to end the line. Write the following line inside your vimrc file:
imap <C-l> <Esc>$a
What does the line say? It maps Ctrl+l to a series of commands. It is equivalent to you pressing Esc (command mode), $ (end of line), a (append) at once.
Or there's the obvious answer: use the End key to go to the end of the line.
Possibly unrelated, but if you want to start a new line after the current line, you can use o anywhere in the line.
The easiest option would be to key in $. If you are working with blocks of text, you might appreciate the command { and } in order to move a paragraph back and forward, respectively.
I was used to Home/End getting me to the start and end of lines in Insert mode (from use in Windows and I think Linux), which Mac doesn't support. This is particularly annoying because when I'm using vim on a remote system, I also can't easily do it. After some painful trial and error, I came up with these .vimrc lines which do the same thing, but bound to Ctrl-A for the start of the line and Ctrl-D for the end of the line. (For some reason, Ctrl-E I guess is reserved or at least I couldn't figure a way to bind it.) Enjoy.
:imap <Char-1> <Char-15>:normal 0<Char-13>
:imap <Char-4> <Char-15>:normal $<Char-13>
There's a good chart here for the ASCII control character codes here for others as well:
http://www.physics.udel.edu/~watson/scen103/ascii.html
You can also do Ctrl-V + Ctrl- as well, but that doesn't paste as well to places like this.

Resources