Indenting Fortran code in Vim - vim

I have a fortran code which looks like this:
open(2,file=filenm(i),status='unknown')
do j=1,num_lines
do k=1,dime
read(2,*) z(k)
enddo
if( j .ge. 1000 ) then
do k=1,dime
sumz(k)=sumz(k)+z(k)
enddo
nsteps=nsteps+1.0
endif
enddo
close(2)
as you can see the indentation is not even, I would like to have something
like this:
open(2,file=filenm(i),status='unknown')
do j=1,num_lines
do k=1,dime
read(2,*) z(k)
enddo
if( j .ge. 1000 ) then
do k=1,dime
sumz(k)=sumz(k)+z(k)
enddo
nsteps=nsteps+1.0
endif
enddo
close(2)
I can go line by line fixing the indentation but the code is kind of big.
I appreciate any comment.

I've gone through a very similar process of trying to get Fortran indenting to work in vim. I still don't have it great, but I've made some progress. The script that arutaku posted (http://www.vim.org/scripts/script.php?script_id=2299) is where I started, but you need to make sure that filetype plugin indent on is in your vimrc.
I also needed a script for determining if I was using fixed-form or free-form syntax, since in my environment I use both. This is recommended in the documentation (http://vimdoc.sourceforge.net/htmldoc/syntax.html#ft-fortran-syntax). As it specifies, I put this script in ~/.vim/ftplugin/fortran.vim:
let s:extfname = expand("%:e")
if s:extfname ==? "f90"
let fortran_free_source=1
unlet! fortran_fixed_source
else
let fortran_fixed_source=1
unlet! fortran_free_source
endif
I also use a script so that I can press F7 to automatically complete certain constructs: http://www.vim.org/scripts/script.php?script_id=2487. I also put that in ~/.vim/ftplugin/.
I also have these in my vimrc to try to improve things further:
let fortran_do_enddo=1
let fortran_more_precise=1
let fortran_have_tabs=1
I believe those are supposed to interact with the first script to control its behavior, but I'm not convinced that they all work for me. I know the first is supposed to properly indent do/enddo blocks. The issue there is that since old-style Fortran allows a do without a matching enddo, the script can't indent them properly unless you can guarantee that you won't use unmatched 'do' statements. The let fortran_do_enddo=1 is supposed to be that guarantee, but it doesn't seem to work for me. The last one is supposed to allow usage of the tab character, which old Fortran considered bad, so it prevents them from being marked as errors. That one appears to work for me. And to be honest, I don't remember what the middle one is supposed to do nor if it works for me.
Edit:
I discovered that there was an older version of the the first script in my vim installation directory (/usr/share/vim/vim70/indent/ in my case) to which I do not have access rights. You might have those rights, and if it's causing you problems, overwrite or delete it. If, like me, you can't edit it, you can get the version in your $HOME to overwrite the functions from the first. I did this by doing two things. First I had to remove the checks to see if the functions already exist (the statements like if exists("*FortranGetFixedIndent")) and then I had to change all the function declarations to force overwriting by using the ! character, i.e. function! SebuFortranGetFreeIndent(). As far as I can tell, everything now works roughly as I would expect!

Does gg=G work?
gg: go to top
=: indent...
G: ... until the end

Try: https://sourceforge.net/projects/findent/files/
From the README:
findent: indents/beautifies/converts Fortran sources
findent supports Fortran-2008
findent can convert from fixed form to free form
binaries for Unix and Windows (findent and findent.exe respectively)
wrapper for processing one or more files in one call available for Unix and Windows (wfindent and wfindent.bat respectively)
(g)vim users: findent can act as a plug-in to format your edit file with the '=' command
gui frontent available in a separate package: jfindent

You can use auto-indentation writing <x>== (in command mode) where x is the number of lines to be indented.
If vim does not have fortran indentation you can load the following plugin and try the == combination: http://www.vim.org/scripts/script.php?script_id=2299

Related

How do I stop vim reading in the default syntax?

I have defined my own javascript syntax file, which is in ~/.vim/syntax/after/
The problem is that the default syntax file that exists in /usr/share/vim/vim82/syntax is loaded along side my custom syntax file (it seems to be loaded before my custom syntax).
The result is that it conflicts with my custom syntax.
How do I ONLY load my custom syntax file? Not the default one.
Of course I could just delete the default one (which works), but that seems like a not very robust fix to the problem considering it will just be put back there when vim is updated.
I have "syntax clear" at the top of my custom file but it doesn't help.
I also note that the default syntax file has the following at the top:
if !exists("main_syntax")
" quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
let main_syntax = 'javascript'
elseif exists("b:current_syntax") && b:current_syntax == "javascript"
finish
endif
But that doesn't do anything either.
I have also tried putting the syntax folder in .vim/syntax, as suggested on the official vim page, but that doesn't seem to do anything at all (as in, it's not read at all).
Thankyou.
In principle, the order in which syntax scripts are sourced is the following:
~/.vim/syntax/foo.vim
$VIMRUNTIME/syntax/foo.vim
~/.vim/after/syntax/foo.vim
~/.vim/after/syntax/ comes last. It is not a good place if you are writing a complete replacement of a built-in syntax script because you have at least one syntax script sourced before yours. On the other hand, it is a good place if what you want to do is either add your own stuff or selectively override stuff that has been set earlier.
$VIMRUNTIME/syntax/ is not a good place either, because it is a systemwide location. Your customisation is supposed to happen in your $HOME, right?.
~/.vim/syntax/ comes first so it is the ideal place for custom syntax scripts, if you add the following line:
let b:current_syntax = "javascript"
This is because $VIMRUNTIME/syntax/javascript.vim begins with the following boilerplate:
if !exists("main_syntax")
" quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
let main_syntax = 'javascript'
elseif exists("b:current_syntax") && b:current_syntax == "javascript"
finish
endif
which, essentially, throws the towel if b:current_syntax is set, and ends with:
let b:current_syntax = "javascript"
to "mark its territory", if you will.
You don't have to check for anything because you come first, but you still have to tell other syntax scripts to mind their own business.
Note that bad mannered syntax scripts may not check for that buffer-local variable so it is entirely possible to still have conflicts even if you are doing the right thing. But that's the nature of Vim.

Using vimscript to run test scripts by utilizing normal vim commands

I started using VIM as my editor around six months back and I enjoy it very much. However, there are a few work related scripts that I'd like to implement to make my life easier. If there is anyone who can help me I would be grateful.
This is my question. I have some tests written in python and I wrote a key mapping to run those tests using vim terminal. It works perfectly. However, now I want to use VimScript and some vim functions to make it look better. I'm a beginner in VimScript and therefore, I'm not sure whether this is doable.
My folder structure looks like,
.
├── my_test.py
└── test
└── testRunner.py
1 directory, 2 files
My test code looks something like,
my_test.py:
#!/bin/python
class MyTest1:
def Run():
# Test body
class MyTest2:
def Run():
# Test body
test/testRunner.py:
#!/bin/python
print "Running the test"
My current key-mapping in .vimrc looks like:
nnoremap <leader>t mZ/class<CR>Nwyiw:noh<CR>:terminal<CR>cd test<CR>python testRunner.py <C-W>"0<CR><C-W><C-W>'Z
What this does is,
Find the test name (the test that I'm currently editing)
Copy the name and run that test name in a vim-terminal
What I want it to be something which looks like:
nnoremap <leader>t :call RunThisTest()<CR>
function! RunThisTest()
RememberEditContext()
FindAndCopyTestName()
RunTestInTestDirectory()
ReturnToEditContext()
endfunction
Can someone help me in developing these functions?
Thank you in advance!
One option is to use the :normal! command directly, which allows you to run a sequence of keystrokes directly as you'd have used them in a mapping.
But it turns out we can do better, much better, so let's get to it!
Searching and Matching
You can use the search() function to look for the class you're in. You can pass it flags, such as bcnW, to have it search backwards, possibly match at the cursor position, do not move the cursor and do not wrap around the file. Putting it all together:
let line = search('^class \w', 'bcnW')
This will return a line number if there was a positive match, or 0 if there wasn't one. If there was a match, we can use getline() to get its contents and then matchlist() to capture the name of the class.
let [_, classname; _] = matchlist(getline(line), '^class \(\w\+\)')
As you can see, using Vimscript we were able to get the classname without moving the cursor and without touching the search register. So we didn't need to set any marks and we won't need to worry about recovering the current position and view!
Running a command
Now it's time to run a command on the terminal. We can simplify the process by passing it a command directly. (Note that there's a difference here, in that the terminal will run just that command, it won't leave the shell around after finished. Depending on your use case, you might prefer to do something more akin to what you're doing now.)
We can run the command in a terminal with:
:terminal ++shell cd test && python testRunner.py MyTest1
But, of course, we need to actually pass it the class name we got, not a fixed value here. We can use the :execute command for this purpose. It takes a string and runs it as a Vimscript command. We can use this to assemble the string dynamically.
execute "terminal ++shell cd test && python testRunner.py ".shellescape(classname)
Finally, to go back to the original window, we can use the :wincmd command, more specifically wincmd p.
Putting it together
The resulting function is:
function! RunThisTest() abort
let line = search('^class \w', 'bcnW')
if line == 0
echoerr "Not inside a test class!"
return
endif
let [_, classname; _] = matchlist(getline(line), '^class \(\w\+\)')
execute "terminal ++shell cd test && python testRunner.py ".shellescape(classname)
wincmd p
endfunction
nnoremap <silent> <leader>t :call RunThisTest()<CR>
There's definitely room for improvement, but this should get you started!
Saving and restoring context
We didn't go into saving and restoring context, since this case actually didn't need any of that!
If you were to develop functions that use commands that affect global context, you can use Vimscript to save and restore it.
For example, if you're going to search, you can save the #/ register and restore it after the search:
let saved_search = #/
/class
let #/ = saved_search
If you're going to yank into a register, you can save and restore it too. For example, #" for the default register. You should also save the register type, which records whether the contents were taken in a character-wise, linewise or blockwise context.
let saved_register = getreg('"')
let saved_regtype = getregtype('"')
normal! y3W
let words = getreg('"')
call setreg('"', saved_register, saved_regtype)
You can also save the current view, which includes the position your cursor is in, but also the other parameters of the window, such as what the first displayed line and column are, such that you can fully restore that context. See the winsaveview() and winrestview() functions for details on that.
Managing Terminals
There are functions to control the terminal that go way beyond what :terminal can do.
For instance, the much richer term_start() allows running a command as a list and passing options such as 'cwd' to run the command on a different directory.
So we could simplify our test execution with:
call term_start(['python', 'testRunner.py', classname], {'cwd': 'test'})
There's also term_sendkeys() which you can use to send keystrokes to the terminal. For example, if you prefer to start a shell and call the Python script through the shell:
let termbuf = term_start(&shell, {'cwd': 'test'})
call term_sendkeys(termbuf, "python testRunner.py ".shellescape(classname)."\r")
You can also use term_getline(termbuf, '.') to get the contents of the line where the cursor currently is. For instance, you could use that to detect whether the terminal is on a shell prompt (line ending in $ and whitespace) or still on an execution of a test runner.
Finally, you can even have the command running inside the terminal call Vim commands! Through special escape sequences, it can call exported functions or ask Vim to open files for editing. See :help terminal-api for details.
Learning More
This is all very neat... But how can I learn more?
My first strong recommendation would be to read the excellent "Learn Vimscript the Hard Way", by Steve Losh. It covers the basics of the language, how to interface with the editor (mappings, auto-commands, indentation expressions, filetypes) and basics of how to put together Vim plug-ins. It also covers common pitfalls of Vimscript and best practices for writing reliable code. That's a must if you want to get serious about scripting Vim.
Second suggestion is read the excellent documentation that's available through :help! Few applications are as well documented as Vim is, so knowing your way around the help system can really help a lot.
Third is using StackExchange. In particular, the Vi & Vim SE which is dedicated to the subject. Not only you'll find great answers there and you'll be able to ask great questions, you will also have the opportunity of seeing great questions, wonder how to solve them and possibly take a stab at writing an answer. (Personally, since I started using the Vi & Vim SE, my Vim-foo has greatly improved, to the point I can consider myself almost an expert.) I strongly recommend that.
Finally, practice. It typically takes a few attempts to get something really right. But the fact that the environment is fairly dynamic and flexible allows for experimentation. You can type and experiment with the commands in the editor itself, so it's usually quick to test your code and get it right as you're writing it.

Vim: How to handle newlines when storing multiple commands in registers?

I have a file where I store snippets of vim commands. When I need a snippet, I yank it and then execute it with #". The snippets are stored as a script, one line per command, like this:
:s/foo/bar/g
:echo "hello"
:s/1/2/g
Edit: I removed normal mode commands from the example, as they were not part of the problem.
Now this procedure doesn't work anymore: when executing the snippet, it just stops at the first line as if waiting for a newline.
Is there an option somewhere affecting how # is executed? I'm pretty sure it was working some time ago...
Substituting the newline with a ^M character works but makes the file more difficult to handle.
Additional information:
Here's another symptom: when I yank a snippet, if I execute it with #" it stops at the first line as I just explained. But if I execute it with :# it works. But the help file doesn't seem to imply any difference in how the two commands treat the register's content...
I don't think the problem is ^M vs. ^J. Vim macros will treat either one as a valid end-of-line character for recorded macros. I think the problem is extra newlines.
In your example, there's at least one spurious newline after 2j, and unless you're particularly careful when copying the snippet, there's probably another one after 10k as well. These extra newlines are like pressing <Enter> in Normal mode -- they move the cursor down one line.
Here's what I think you want the snippet to look like:
:s/foo/bar/g
2j:s/1/2/g
10k
(Even that's a little misleading -- you'd still have to be careful not to copy the newline after the 10k.)
Why do these extra newlines make such a big difference? Well, for one thing, they cause you to be at least one line away from where you expect to be, which throws off anything you want to do on a particular line (like execute the :s// command).
More importantly, however -- and this is what I think is happening in your example -- is that Vim stops macro playback if the macro attempts to use <Enter> on the last line of a buffer. (I'm guessing Vim considers it an error, and any error causes a macro to stop running.)
Here's an example. Suppose you've got this snippet stored in register x:
4j
:echo "Done"
(Notice the newline after 4j.)
Furthermore, suppose you have the following five lines (and only these five lines) in a buffer:
line 1
line 2
line 3
line 4
line 5
If you now press #x on line 1, the :echo "Done" never executes. Vim moves the cursor down 4 lines to line 5, then attempts to move down one more line because of the extra newline, but it can't. The macro stops executing at that point, before the :echo command gets a chance to run.
However, it works if you change the x register to this:
4j:echo "Done"
So to return to your original example, I'll bet what's happening is that the extra newline after 2j is attempting to move your cursor somewhere it can't go, and that causes the macro to stop. The bottom line of the screen contains the last command executed (:s/foo/bar/g), which makes it look like Vim is waiting for you to press Return.
Finally, I'd strongly recommend using another method to store and execute Vim command sequences. The technique you're using is tolerable for simple cases, but it's fragile and doesn't scale well. Vim has a full scripting language that includes functions and custom commands, and it can be used to do all the things you're doing now, but in a much more robust fashion. Vim scripting is a big topic, but I'd start here:
:help script
Be sure to read about the :normal command, which lets you execute Normal-mode commands (like 2j and 10k) within scripts.
Good luck!
I finally found the culprit. Somehow I had a command mapping on <C-J> in my .vimrc file. When read with the default cpoptions, this turned into a mapping on <NL>.
How I found out: I noticed that when starting vim with -u ~/.vimrc, it would indeed execute yanked snippets. I generated a session file with and without that commandline option and compared them. This way I found out that a different set of cpoptions where used to read the same .vimrc file, so that in one case the mapping was indeed on <C-J>, in the other it was converted into a mapping on <NL>!
If someone has a similar problem, I suggest to look carefully at the currently set command mappings, with :cmap.

Is it possible to format C++ code with VIM?

I am rather new to VIM. I got some source code and this is a mess. At a first sight I would like at least to get a clear and organised view of the code, so I like to get it rightly formatted, I mean indented depending on the depth of the functions and so.
I wonder if it can be done with VIM, and otherwise which other commandline tools for that can you recommend.
Thanks
While vim is a true Swiss-knife I still prefer external tools for some jobs. This approach is some times much more intuitive and easy to remember than using the built-in equivalent.
In the case of indenting, I filter the whole file buffer through astyle. The astyle parameters are much easier to grasp in a couple of minutes, especially if you are not a vim guru. Also astyle provides much more flexibility in fine-tuning the output.
First install astyle:# apt-get install astyle
Then inside vim:
:%!astyle (simple case - astyle default mode is C/C++)
or
:%!astyle --mode=c --style=ansi -s2 (ansi C++ style, use two spaces per indent level)
or
:1,40!astyle --mode=c --style=ansi (ansi C++ style, filter only lines 1-40)
you can do the following:
gg=G
I would highly recommend clang-format nowadays. It allows simple integration of clang-format into Vim, once you have clang-format installed:
http://clang.llvm.org/docs/ClangFormat.html#vim-integration
It is the only code beautifier that really understands your C++ code, and it is really intelligent to beautify the code more like a human being than a machine. E.g.:
void TestFunction(int argument1, int argument2,
int argument3);
void TestFunctionVeryLongName(int argument1,
int argument2,
int argument3);
void TestFunctionWithRidiculouslyLongName(
int argument1, int argument2, int argument3);
Vim will definitely do this, although the results may not be perfect:
First, select the entire file in visual mode: ggVG
Then hit = to reindent everything.
You can learn more about the equal command with: :help =
There is also a Vim plugin relying on clang-format: vim-clang-format
Then you can simply map the formatting command to whatever suits you.
There is a vim plugin that enables formatting on your code from within vim. It's called vim-autoformat and you can download it here:
https://github.com/vim-autoformat/vim-autoformat
It integrates external code-formatting programs into vim. For example, if you want to format C, C++, C# or Java code, you need to install the program astyle, and vim sets it as the format program automatically.
I don't write C++ code, but I write some Java code.
Instead, Vim supports the formatting of some common languages.
I have set up a short cut for me to format the whole code in the buffer.
It will return to the line I just edited :)
" format the file
map <leader>fm gg=G'.
A generic solution along the lines of m000's idea is to use UniversalIndentGUI as an external tool.
Just had to solve this exact problem, so I thought I'd contribute to save others some time.
You can use gg=G to indent your code. But things get hard to understand the moment you want to tweak how that auto-indenting happens. Therefore, if you only care that errant whitespace is removed and don't really care about formatting style, gg=G is the quickest way to go about it, because its built-in.
If you do want to control the style (for example, you're trying to make your code conform to a style guide), then you're going to need an external tool to process your file. You can invoke that tool from within vim with: :%!<toolname> <options>. This pipes the file through the tool and re-loads the processed result. (You can obviously use this for anything else you want to do to your file too)
So the next question is, what external tool should you choose? Regardless, the method is the same:
Install the tool of choice
Make sure its in your path
Add a line to your vimrc file that creates a shortcut key to use so you save time
Use it.
Now, which tool you use depends on the style you're trying to replicate. If you're trying to replicate a widely used style, then chances are astyle is all you need.
If you're trying to replicate a custom style, then you will need two things:
UniversalIndentGui - a front end that lets you play around with various options and live-preview their effect on the source file
A set of source code formatting tools installed and in your path
Between uncrustify and greatcode, you should be able to completely replicate the style you want.
Actually, I lied. There is another way and its called clang-format. However, you're going to want to read the documentation on it and its still in early stages so some options don't work very well. It is a beautiful tool though (definitely the smartest of the lot because constructs an AST of your code) and it is even available for Windows.
If you're going to take the time to read the manual, you also want to check out GNU Indent.
Of course, there is the last way, which is actually taking the time to learn vim's indent rules and writing one for your style. It will take time, but it will work with gg=G.
Some notes on astyle vs uncrustify vs greatcode:
Astyle is good for general formatting, but can't do things like align the declaration of variables and re-style comments very well.
Uncrustify can do a LOT of stuff that astyle can't, but be prepared to spend an hour playing around until you've found the correct combination of options you need. (Or if you feel like wasting a lot of time, use genetic algorithms to figure out the best combination of options for your style and when you do share the code and give me a link so I can use it too :) )
Note that you don't have to choose one tool. With vim, you can map one keystroke to execute several commands in succession, so theoretically you could use a combination of these tools to get exactly what you're looking for.
Last but not least, here's an excerpt from my .vimrc file, where I have mapped F12 to invoke astyle with some options:
"A2 = attached brackets
"-s8 indent 8 spaces
"-xc attached braces to class declarations
"-xj remove braces for single statement ifs and elses
"-c convert tabs to spaces in the non-indentation part of the line
map <F12> :%!astyle -A2 -s8 -xc -xj -c<CR>
Don't judge me on the style. Just use the tool to reproduce what you want.

Does Vim have an auto-comment feature based on the file's syntax?

I'm not sure this is possible, but I'm interesting in making this happen.
Ideally, I would like to map this feature to SHIFT+CTRL+3.
I'm looking for a way to have Vim enter a comment (single line) which corresponds to the syntax of the file I'm editing. If there are multiple single-line comment styles, Vim could either automatically pick one, or give me the choice. If the single-line comment has two parts (e.g. /* and */), then pressing SHIFT+CTRL+3 the first time will start the comment, and the second time will close the comment.
Examples:
Python: #
JavaScript: //
C, C++: /* with */ or //
I know there are scripts which will insert comments for you, but I haven't seen any that will do this based on the syntax of the file.
I highly recommend NERD Commenter.
Sort of! I don't believe vim will do this out of the box, but you can install plugins that will do fairly intelligent commenting (using movement keys, visual line highlighting, etc) that are specific to the filetype being edited. You can get these plugins off of vim.org, and you should be able to make your own key mappings in your .vimrc file if you don't like the ones they come with.
tComment is pretty well regarded, and has worked for me.
I've heard that EnhCommentify might be better, but I haven't used it myself.
Seems like a similar question to this:
How to comment in vim while respecting the indent?
Use the nerd commenter plugin:
http://www.vim.org/scripts/script.php?script_id=1218
See: this script which provides a function to commented a highlighted area in visual mode.
You want to start a comment in insert mode so your function would look more like:
fun CommentLines()
exe ":s#^#".g:Comment."#g"
endfun
Not quite what you're looking for, but efficient, and I suppose you know which comment to use.
(all this in command mode)
Put your cursor to the first line you want to comment. We willl then set a marker called a (valid names are a-z, single character) by typing
ma
put the cursor to the last line, then set a marker called b by typing
mb
Then comment the whole block (by searching for a newline and inserting the comment character (note the use of "#" as search delimiter because otherwise wee have to escape the "/")
:'a,'bs#^#//#
or for Python:
:'a,'bs/^/#/
To uncomment:
:'a,'bs#^//##
As we do line comments, it doesn't matter if we have other comments already in the file, they will be preserved.

Resources