Preserve indentation in C++ comments in vim - c++

Is it possible to configure vim and cindent to not alter indentation in c++ comments when reindenting the file (gg=G) ?
I have some formated lists in comments aligned with 4 spaces but vim interpret this as bad indent and realign everything.
For example:
/**
my list:
* item 1
* item 2
*/
becomes:
/**
my list:
* item 1
* item 2
*/
I want a way to tell vim: "Don't touch to comments content but indent everything else."
It is important because our project use doxygen with a markdown like parser to generate documentation and indentation is used by list levels.

How about writing like this so in-comment indentation is independent of comment indentation:
/**
* my list:
* * item 1
* * item 2
*/

As suggested by review, I repost an answer with answer from vi stackexchange community here:
I don't believe it's possible to achieve this with 'cinoptions'.
The correct solution is probably to write a new indentexpr that applies C-indenting (accessible via the cindent() function) only to lines that aren't within comments.
However, here's a couple of quick and dirty solutions:
I skipped first solution which I don't use and is therefore not the answer. You can still see it on the original post.
Using a Function
function! IndentIgnoringComments()
let in_comment = 0
for i in range(1, line('$'))
if !in_comment
" Check if this line starts a comment
if getline(i) =~# '^\s*/\*\*'
let in_comment = 1
else
" Indent line 'i'
execute i . "normal =="
endif
else
" Check if this line ends the comment
if getline(i) =~# '\*\/\s*$'
let in_comment = 0
endif
endif
endfor
endfunction
You can run this with :call IndentIgnoringComments() or you could set up a command or a mapping. e.g.:
nnoremap <leader>= :call IndentIgnoringComments()<CR>
I personaly defined a command which call this function and combine it with another reformating I apply often on files in this project (:%s/\s*$//g).
Thank to Rich on https://vi.stackexchange.com
Original post: https://vi.stackexchange.com/a/13962/13084

Related

Regex (re2 googlesheets) multiple values in multiline cell

Getting stuck on how to read and pretty up these values from a multiline cell via arrayformula.
Im using regex as preceding line can vary.
just formulas please, no custom code
The first column looks like a set of these:
```
[config]
name = the_name
texture = blah.dds
cost = 1000
[effect0]
value = 1000
type = ATTR_A
[effect1]
value = 8
type = ATTR_B
[feature0]
name = feature_blah
[components]
0 = comp_one,1
[resources]
res_one = 1
res_five = 1
res_four = 1
<br/>
Where to be useful elsewhere, at minimum it needs each [tag] set ([effect\d], [feature\d], ect) to be in one column each, for example the 'effects' column would look like:
ATTR_A:1000,ATTR_B:8
and so on.
Desired output can also be seen in the included spreadsheet
<br/>
<b>Here is the example spreadsheet:</b>
https://docs.google.com/spreadsheets/d/1arMaaT56S_STTvRr2OxCINTyF-VvZ95Pm3mljju8Cxw/edit?usp=sharing
**Current REGEXREPLACE**
Kinda works, finds each 'type' and 'value' great, just cant figure out how to extract just that from the rest, tried capture (and non-capturing) groups before and after but didnt work
=ARRAYFORMULA(REGEXREPLACE($A3:$A,"[\n.][effect\d][\n.](.)\n(.)","1:$1 2:$2"))
**Current SUBSTITUTE + REGEXEXTRACT + REGEXREPLACE**
A different approach entirely, also kinda works, longer form though and left with having to parse the values out of that string, where got stuck again. Idea was to use this to simplify, then regexreplace like above. Getting stuck removing content around the final matches though, and if can do that then above approach is fine too.
// First ran a substitute
=ARRAYFORMULA(SUBSTITUTE(SUBSTITUTE($A3:$A,char(10),";"),";;",char(10)))
// Then variation of this (gave up on single line 'effect/d' so broke it up to try and get it working)
=ARRAYFORMULA(IF(A3:A<>"",IFERROR(REGEXEXTRACT(A3:A,"(?m)^(?:[effect0]);(.)$")&";;")&""&IFERROR(REGEXEXTRACT(A3:A,"(?m)^(?:[effect1]);(.)$")&";;")&""&IFERROR(REGEXEXTRACT(A3:A,"(?m)^(?:[effect2]);(.)$")&";;"),""))
// Then use regexreplace like above
=ARRAYFORMULA(REGEXREPLACE($B3:$B,"value = (.);type = (.);;","1:$1 2:$2"))
**--EDIT--**
Also, as my updated 'Desired Output' sheet shows (see timestamped comment below), bonus kudos if you can also extract just the values of matching 'type's to those extra columns (see spreadsheet).
All good if you cant though, just realized would need that too for lookups.
**--END OF EDIT--**
<br/>
Ive tried dozens of things, discarding each in turn, had a quick look in version history to grab out two promising attempts and shared them in separate sheets.
One of these also used SUBSTITUTE to simplify input column, im happy for a solution using either RAW or the SUBSTITUTE results.
<br/>
**Potentially Useful links:**
https://github.com/google/re2/wiki/Syntax
<br/>
<b>Just some more words:</b>
I also have looked at dozens of stackoverflow and google support pages, so tried both REGEXEXTRACT and REGEXREPLACE, both promising but missing that final tweak. And i tried dozens of tweaks already on both.
Any help would be great, and hopefully help others in future since examples with spreadsheets are great since every new REGEX seems to be a new adventure ;)
<br/>
P.S. if we can think of better title for OP, please say in comment or your answer :)
paste in B3:
=ARRAYFORMULA(SUBSTITUTE(TRIM(TRANSPOSE(QUERY(TRANSPOSE(
IF(C3:E<>"", C2:E2&":"&C3:E, )),,999^99))), " ", ", "))
paste in C3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT($A3:$A, "(\d+)\ntype = "&C2)))
paste in D3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT($A3:$A, "(\d+)\ntype = "&D2)))
paste in E3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT($A3:$A, "(\d+)\ntype = "&E2)))
paste in F3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT(A3:A, "\[feature\d+\]\nname = (.*)")))
paste in G3:
=ARRAYFORMULA(IFNA(REGEXEXTRACT(A3:A, "\[components\]\n\d+ = (.*)")))
paste in H3:
=ARRAYFORMULA(IFNA(REGEXREPLACE(INDEX(SPLIT(REGEXEXTRACT(
REGEXREPLACE(A3:A, "\n", ", "), "\[resources\], (.*)"), "["),,1), ", , $", )))
spreadsheet demo
This was a fun exercise. :-)
Caveat first: I have added some "input data". Examples:
[feature1]
name = feature_active_spoiler2
[components]
0 = spoiler,1
1 = spoilerA, 2
So the output has "extra" output.
See the tab ADW's Solution.

Markdown: lists are not well converted

I'm trying to create a list in Markdown. As I've read in some documentation, if I write this Markdown code:
My list
* first item
* second item
* third item
Not in the list
I would get as result the same as if I write this in HTML:
<p>My list</p>
<li>
<ul>first item</ul>
<ul>second item</ul>
<ul>third item</ul>
</li>
<p>Not in the list</p>
I use Atom as editor and its Markdown previewer and everything is OK, but when I use pandoc to convert my Markdown file as follows:
pandoc test.md -o test.odt
what I get is this:
My list * first item * second item * third item
Not in the list
Where am I doing wrong?
There are two possible solutions to your problem:
Add a blank line between the paragraph and the list (as #melpomene mentioned in a comment).
My list
* first item
* second item
* third item
Not in the list
Leave out the blank line and tell Pandoc to use commonmark as the input format rather than the default, markdown.
pandoc -f commonmark -o test.odt test.md
The "problem" is that the Atom editor uses a CommonMark parser and, by default, Pandoc uses an old-school Markdown parser which mostly follows these rules and the reference implementation (markdown.pl). In fact, the Commonmark spec specifically acknowledges this difference:
In CommonMark, a list can interrupt a paragraph. That is, no blank
line is needed to separate a paragraph from a following list:
Foo
- bar
- baz
<p>Foo</p>
<ul>
<li>bar</li>
<li>baz</li>
</ul>
Markdown.pl does not allow this, through fear of triggering a list
via a numeral in a hard-wrapped line:
The number of windows in my house is
14. The number of doors is 6.
If you want common behavior among your tools, then you need to only use tools which follow the same behavior.

VIM - Hotkey for VIMGREP on Visual Selection in current buffer

How would I go about setting up a hotkey (eg: CTRL+g) to perform a VIMGREP operation on the current visual selection in the current buffer? My intent is to show a line-numbered list in the "quickfix" window of all matching search results.
Right now, if I want to get a list of results for a regex search, I could do a command-mode query like so:
:vimgrep /foo/ %
However, there are two problems with this:
I don't want to have to type out the entire query. I could always do a visual selection, then use CTRL+r, CTRL+w, to paste the current visual selection into the command buffer, but I'd like something simpler than this.
The above approach requires that the current buffer is already saved to a file. I'd like to be able to work on a temporary buffer I've pasted into VIM rather than having to save a file buffer each time I want to do this.
Thank you.
A low-level solution
Try [I and the :ilist command:
[I " lists every occurrence of the word under the cursor
" in the current buffer (and includes)
:ilist /foo<CR> " lists every occurrence of foo in the current buffer
" (and includes)
Press : followed by a line number and <CR> to jump to that line.
You can use them on the visual selection with a simple mapping:
xnoremap <key> "vy:<C-u>ilist /<C-r>v<CR>:
You'll probably need to sanitize the register upon insertion, though.
See :help :ilist.
Another even lower-level solution
Since we are at it, let's dig even deeper and find the amazingly simple and elegant:
:g/foo/#
that you could use in the same way as :ilist above:
xnoremap <key> "vy:<C-u>g/<C-r>v/#<CR>:
Limitations
The solutions above don't use the quickfix window, obviously, but they allow you to:
see their result as a list,
use line numbers to actually get to where you want.
They have limitations, though:
the list is not cached so you must perform the search again if you want to get to a different occurrence,
the list is not transient like the quickfix list so you can't use navigation commands like :cnext or :clast to move around the result.
A higher-level solution
If those limitations are a showstopper, the function below, adapted from justinmk's answer in this /r/vim thread, gives you an almost complete solution:
press [I in normal mode to search for the word under the cursor in the whole buffer,
press ]I in normal mode to search for the word under the cursor after the current line,
press [I in visual mode to search for the selected text in the whole buffer,
press ]I in visual mode to search for the selected text after the current line.
The function below uses the quickfix list/window when the buffer is associated to a file and falls back to the regular behavior of [I and ]I otherwise. It could probably be modified to be used as part of an :Ilist command.
" Show ]I and [I results in the quickfix window.
" See :help include-search.
function! Ilist_qf(selection, start_at_cursor)
" there's a file associated with this buffer
if len(expand('%')) > 0
" we are working with visually selected text
if a:selection
" we build a clean search pattern from the visual selection
let old_reg = #v
normal! gv"vy
let search_pattern = substitute(escape(#v, '\/.*$^~[]'), '\\n', '\\n', 'g')
let #v = old_reg
" and we redirect the output of our command for later use
redir => output
silent! execute (a:start_at_cursor ? '+,$' : '') . 'ilist /' . search_pattern
redir END
" we are working with the word under the cursor
else
" we redirect the output of our command for later use
redir => output
silent! execute 'normal! ' . (a:start_at_cursor ? ']' : '[') . "I"
redir END
endif
let lines = split(output, '\n')
" better safe than sorry
if lines[0] =~ '^Error detected'
echomsg 'Could not find "' . (a:selection ? search_pattern : expand("<cword>")) . '".'
return
endif
" we retrieve the filename
let [filename, line_info] = [lines[0], lines[1:-1]]
" we turn the :ilist output into a quickfix dictionary
let qf_entries = map(line_info, "{
\ 'filename': filename,
\ 'lnum': split(v:val)[1],
\ 'text': getline(split(v:val)[1])
\ }")
call setqflist(qf_entries)
" and we finally open the quickfix window if there's something to show
cwindow
" there's no file associated with this buffer
else
" we are working with visually selected text
if a:selection
" we build a clean search pattern from the visual selection
let old_reg = #v
normal! gv"vy
let search_pattern = substitute(escape(#v, '\/.*$^~[]'), '\\n', '\\n', 'g')
let #v = old_reg
" and we try to perform the search
try
execute (a:start_at_cursor ? '+,$' : '') . 'ilist /' . search_pattern . '<CR>:'
catch
echomsg 'Could not find "' . search_pattern . '".'
return
endtry
" we are working with the word under the cursor
else
" we try to perform the search
try
execute 'normal! ' . (a:start_at_cursor ? ']' : '[') . "I"
catch
echomsg 'Could not find "' . expand("<cword>") . '".'
return
endtry
endif
endif
endfunction
nnoremap <silent> [I :call Ilist_qf(0, 0)<CR>
nnoremap <silent> ]I :call Ilist_qf(0, 1)<CR>
xnoremap <silent> [I :<C-u>call Ilist_qf(1, 0)<CR>
xnoremap <silent> ]I :<C-u>call Ilist_qf(1, 1)<CR>
NB: <C-r><C-w> inserts the word under the cursor, not the visual selection for which there's unfortunately no such shortcut. We have no choice but to yank.
Grepping a scratch buffer
You can use the :global command combined with :caddexpr to add entries to the current quickfix list. Here is the example from :h :caddexpr:
:g/mypattern/caddexpr expand("%") . ":" . line(".") . ":" . getline(".")
There are a few issues with this:
This approach only does one match per line
Does not start a new quickfix list
Really long to type out
Assumes the default global 'errorformat' hasn't been changed
To overcome these issues (all but the multiple matches per line) put the following command in your ~/.vimrc file:
command! -nargs=1 -bar Cgrep
\ let s:errorformat = &errorformat |
\ try |
\ let &errorformat='%f:%l:%m' |
\ cexpr [] |
\ execute 'g'.<q-args>.'caddexpr expand("%").":".line(".").":".getline(".")' |
\ cc |
\ finally |
\ let &errorformat = s:errorformat |
\ endtry
Now you can use :Cgrep/foo/ to grep the current buffer.
A visual mapping
To make it so you can do a visual version of this you need to yank in the selected text and pass it to our :Cgrep command via <c-r>. Here is an example visual mapping g/ to do just that:
xnoremap g/ y:<c-u>Cgrep/<c-r>"/<cr>
There are some issues with this mapping too:
This clobber the unnamed register, #"
This assumes the visually selected text will be a valid pattern
The following mapping fixes the mapping by using the expression register via <c-r>= and very no magic, \V:
xnoremap g/ :<c-u>let #/=#"<cr>gvy:let [#/,#"]=[#",#/]<cr>Cgrep/\V<cr>=substitute(escape(#/,'/\'),'\n','\\n','g')<cr>/<cr>
Conclusion
Personally I would forgo the mapping and get a visual star plugin (there are few out there). There is a nice Vimcast about this: Search for the selected text. I would then use that with the :Cgrep command we just created via :Cgrep// or better yet xmap g/ *:Cgrep//<cr>
For more help see:
:h :caddexpr
:h :cexpr
:h :g
:h 'efm
:h registers
:h /\V
To search for the visual selected text in files *.c via the hotkey CTRL+g do:
:vmap <silent> <unique> <c-g> y:vimgrep "<c-r>"" *.c<CR>
Two problems remain:
You want to search in a buffer, not in a file.
You want line numbers in the quickfix.
To 1:
As far as I know vimgrep can only search in files. The solution would be to write the buffer in a temporary file and search in this file and delete the temporary file when it is no longer needed. This solution requires a script which is called via the hotkey.
Just a hint: To get a suitable filename the VIM function tempname() can be used. Example:
let s:tmpfile = tempname()
(Sorry, I currently have no time to show a script solution here, maybe I add one later. Maybe somebody else has a better solution or can provide a script?)
To 2:
This command will enable line number in the current buffer:
:set number

Mallet in R regex error :java.lang.NoSuchMethodException: No suitable method for the given parameters

Ive been following the tutorial on how to use mallet in R to create topic models. My text file has 1 sentence per line. It looks like this and has about 50 sentences.
Thank you again and have a good day :).
This is an apple.
This is awesome!
LOL!
i need 2.
.
.
.
This is my code:
Sys.setenv(NOAWT=TRUE)
#setup the workspace
# Set working directory
dir<-"/Users/jxn"
Dir <- "~/Desktop/Chat/malletR/text" # adjust to suit
require(mallet)
documents1 <- mallet.read.dir(Dir)
View(documents1)
stoplist1<-mallet.read.dir("~/Desktop/Chat/malletR/stoplists")
View(stoplist1)
**mallet.instances <- mallet.import(documents1$id, documents1$text, "~/Desktop/Chat/malletR/stoplists/en.txt", token.regexp ="\\p{L}[\\p{L}\\p{P}]+\\p{L}")**
Everything works except for the last line of the code
**`**mallet.instances <- mallet.import(documents1$id, documents1$text, "~/Desktop/Chat/malletR/stoplists/en.txt", token.regexp ="\\p{L}[\\p{L}\\p{P}]+\\p{L}")**`**
I keep getting this error :
Error in .jcall("RJavaTools", "Ljava/lang/Object;", "invokeMethod", cl, :
java.lang.NoSuchMethodException: No suitable method for the given parameters
According to the package, this is how the function should be:
mallet.instances <- mallet.import(documents$id, documents$text, "en.txt",
token.regexp = "\\p{L}[\\p{L}\\p{P}]+\\p{L}")
I believe it has something to do with the token.regexp argument as
documents1 <- mallet.read.dir(Dir) works just fine which means that the first 3 arguments supplied to mallet.instances was correct.
This is a link to the git repo that i was following the tutorial from.
https://github.com/shawngraham/R/blob/master/topicmodel.R
Any help would be much appreciated.
Thanks,
J
I suspect the problem is with your text file. I have encountered the same error and resolved it by using the as.character() function as follows:
mallet.instances <- mallet.import(as.character(documents$id),
as.character(documents$text),
"en.txt",
FALSE,
token.regexp="\\p{L}[\\p{L}\\p{P}]+\\p{L}")
Are you sure you converted the id field also to character ? It is easy to overlook the advice and leave it as an integer.
Also there is a typo in the code sample: the backslashes have to be escaped:
token.regexp = "\\p{L}[\\p{L}\\p{P}]+\\p{L}"
This usually occurs because the html text editor eats up one backslash.

Move to the middle of a block code

Using Vim I'm trying to move the cursor in the middle of a code block, but I can't figure out how to do this :
//cursor is for instance here.
{
//or here
//some code
// .... **** move cursor here ****
//some more code
}
The final idea is to have a shortcut that saves the current position, moves the cursor in the middle of the code block, sets the current line to the middle of the screen (with the shortcut "zz"), and then moves back to the saved position.
I'd prefer a built-in vim function, but a plugin works too.
EDIT: This is for c++ and so I want it for brackets {}.
I gave it a (quick and dirty) go:
function! Middleize()
" use ]M to jump to either the end of the current method if we are in it
" or the start of the next method if we are above the method
normal! ]M
" we record the current line number
let first_line = line('.')
" we go to the other end of the method
normal! %
" we record the current line number
let second_line = line('.')
" we started either from the top or from the bottom of the method
" so we have to take that into account when calculating the number
" of the line we want to jump to
if first_line < second_line
let middle_line = first_line + ((second_line - first_line) / 2)
else
let middle_line = ((first_line - second_line) / 2) + second_line
endif
" let's go!
execute "normal! " . middle_line . "Gzz"
endfunction
nnoremap <F5> :call Middleize()<CR>
More of a general solution but might be useful - the easy-motion plugin allows you to jump all over the place with great precision.
For example:
<Leader><Leader>w (default) - 'word motion'
g
Then to jump back, you'd just do the same thing backwards (in this case, <Leader><Leader>b g.
This doesn't set the current line to the middle of the screen, although you can :set scrolloff=9999 to have the middle of the screen follow your cursor around.
This won't give you exactly what you want, but it'll get text of the function on the screen (assuming it's not too long).
ma - set a mark at the current cursor position.
Repeatedly press } (jump ahead by a paragraph) until you can see the code you want.
`a - return to the mark you set.
A "paragraph" in vim terms is a group of consecutive non-blank lines. It's a nice approximation for a block of code. Also note that you can use any letter for the mark command, so there can be up to 52 of them active at once.