最近需要在linux系統(tǒng)下編輯fortran的代碼呕缭,但是系統(tǒng)自帶的編輯器vim本身對(duì)fortran的支持不夠強(qiáng)大嘱巾,但是好在vim本身是一個(gè)擴(kuò)展性極強(qiáng)的編輯器齐邦,在CSDN上查找到一篇搬運(yùn)的教程演侯,但是本身沒(méi)有寫(xiě)全炕吸,原鏈接又時(shí)效了伐憾,于是倒騰了一上午,結(jié)果如下:
實(shí)現(xiàn)了vim對(duì)fortran語(yǔ)法高亮的優(yōu)化
image.png
自動(dòng)識(shí)別自由格式赫模,自動(dòng)折疊特定模塊
image.png
編輯模式下树肃,按F7自動(dòng)補(bǔ)全語(yǔ)法結(jié)束語(yǔ)句。
image.png
image.png
PS:本人額外添加了許多類(lèi)似的模塊結(jié)束語(yǔ)句補(bǔ)全功能瀑罗。
實(shí)現(xiàn)方法:
1.打開(kāi)vim對(duì)Python的支持
這一步最新版vim已經(jīng)不需要執(zhí)行了胸嘴,因?yàn)榇蠹叶伎缛雙y3的時(shí)代了莉钙,并且這個(gè)教程內(nèi)使用到的py2腳本我也已經(jīng)優(yōu)化成py3格式了~~~
這里說(shuō)的python是指python2+,所以需要用apt從新安裝
輸入sudo apt-get install vim-nox-py2
可以安裝vim的特定Python支持版本,之后需要切換版本則可以使用sudo update-alternatives --config vim
來(lái)切換筛谚。
這時(shí)輸入vim --version | grep python
應(yīng)該可以看見(jiàn):
image.png
2.打開(kāi)~/.vimrc文件
添加如下內(nèi)容
"這是建立的vim配置文件磁玉,需要移植請(qǐng)拷貝致~.vimrc處。
" 這行定義了文字編碼規(guī)則序列
set encoding=utf-8
set fileencodings=ucs-bom,utf-8,utf-16,gbk,big5,gb18030,shift-jis,euc-jp,euc-kr,latin1
set fileencoding=utf-8
"fortran code improve set
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
let fortran_more_precise=1
let fortran_do_enddo=1
"去掉固定格式每行開(kāi)頭的紅色區(qū)域
let fortran_have_tabs=1
"允許折疊
let fortran_fold=1
let fortran_fold_conditionals=1
"折疊方式
set foldmethod=syntax
"加載第三方插件
filetype plugin on
3.在~/.vim/after/indent文件夾內(nèi)添加如下文件
文件命名為fortran.vim
內(nèi)容為:
" Vim indent file
" Language: Fortran 95, Fortran 90 (free source form)
" Description: Indentation rules for continued statements and preprocessor
" instructions
" Indentation rules for subroutine, function and forall
" statements
" Installation: Place this script in the $HOME/.vim/after/indent/ directory
" and use it with Vim 7.1 and Ajit J. Thakkar's Vim scripts
" for Fortran (http://www.unb.ca/chem/ajit/)
" Maintainer: S閎astien Burton <sebastien.burton@gmail.com>
" License: Public domain
" Version: 0.4
" Last Change: 2011 May 25
" Modified indentation rules are used if the Fortran source code is free
" source form, else nothing is done
if (b:fortran_fixed_source != 1)
setlocal indentexpr=SebuFortranGetFreeIndent()
setlocal indentkeys+==~subroutine,=~function,=~forall
setlocal indentkeys+==~endsubroutine,=~endfunction,=~endforall
" Only define the functions once
if exists("*SebuFortranGetFreeIndent")
finish
endif
else
finish
endif
" SebuFortranGetFreeIndent() is modified FortranGetFreeIndent():
" Returns the indentation of the current line
function SebuFortranGetFreeIndent()
" No indentation for preprocessor instructions
if getline(v:lnum) =~ '^\s*#'
return 0
endif
" Previous non-blank non-preprocessor line
let lnum = SebuPrevNonBlankNonCPP(v:lnum-1)
" No indentation at the top of the file
if lnum == 0
return 0
endif
" Original indentation rules
let ind = FortranGetIndent(lnum)
" Continued statement indentation rule
" Truth table (kind of)
" Symbol '&' | Result
" No 0 0 | 0 No change
" Appearing 0 1 | 1 Indent
" Disappering 1 0 | -1 Unindent
" Continued 1 1 | 0 No change
let result = -SebuIsFortranContStat(lnum-1)+SebuIsFortranContStat(lnum)
" One shiftwidth indentation for continued statements
let ind += result*&sw
" One shiftwidth indentation for subroutine, function and forall's bodies
let line = getline(lnum)
if line =~? '^\s*\(\(recursive\s*\)\=pure\|elemental\)\=\s*subroutine\|program\|module'
\ || line =~? '^\s*\(\(recursive\s*\)\=pure\|elemental\)\=\s*'
\ . '\(\(integer\|real\|complex\|logical\|character\|type\)'
\ . '\((\S\+)\)\=\)\=\s*function'
\ || line =~? '^\s*\(forall\)'
let ind += &sw
endif
if getline(v:lnum) =~? '^\s*end\s*\(subroutine\|function\|forall\|program\|module\)'
let ind -= &sw
endif
" You shouldn't use variable names begining with 'puresubroutine',
" 'function', 'endforall', etc. as these would make the indentation
" collapse: it's easier to pay attention than to implement the exceptions
return ind
endfunction
" SebuPrevNonBlankNonCPP(lnum) is modified prevnonblank(lnum):
" Returns the line number of the first line at or above 'lnum' that is
" neither blank nor preprocessor instruction.
function SebuPrevNonBlankNonCPP(lnum)
let lnum = prevnonblank(a:lnum)
while getline(lnum) =~ '^#'
let lnum = prevnonblank(lnum-1)
endwhile
return lnum
endfunction
" SebuIsFortranContStat(lnum):
" Returns 1 if the 'lnum' statement ends with the Fortran continue mark '&'
" and 0 else.
function SebuIsFortranContStat(lnum)
let line = getline(a:lnum)
return substitute(line,'!.*$','','') =~ '&\s*$'
endfunction
4.在~/.vim/ftplugin文件夾下新建
文件名問(wèn):fortran_codecomplete.vim
(文件本身原本使用的python2語(yǔ)法驾讲,我已經(jīng)優(yōu)化成py3語(yǔ)法了蚊伞,并且添加了對(duì)program和module塊的補(bǔ)完操作)
內(nèi)容為:
" File: fortran_codecomplete.vim
" Author: Michael Goerz (goerz AT physik DOT fu MINUS berlin DOT de)
" Version: 0.9
" Copyright: Copyright (C) 2008 Michael Goerz
" This program is free software: you can redistribute it and/or modify
" it under the terms of the GNU General Public License as published by
" the Free Software Foundation, either version 3 of the License, or
" (at your option) any later version.
"
" This program is distributed in the hope that it will be useful,
" but WITHOUT ANY WARRANTY; without even the implied warranty of
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
" GNU General Public License for more details.
"
" Description:
" This maps the <F7> key to complete Fortran 90 constructs"
" Installation:
" Copy this file into your ftplugin directory.
python3 << EOF
import re
import vim
class SyntaxElement:
def __init__(self, pattern, closingline):
self.pattern = pattern
self.closingline = closingline
def match(self, line):
""" Return (indent, closingline) or (None, None)"""
match = self.pattern.search(line)
if match:
indentpattern = re.compile(r'^\s*')
variablepattern = re.compile(r'\$\{(?P<varname>[a-zA-Z0-9_]*)\}')
indent = indentpattern.search(line).group(0)
closingline = self.closingline
# expand variables in closingline
while True:
variable_match = variablepattern.search(closingline)
if variable_match:
try:
replacement = match.group(variable_match.group('varname'))
except:
print("Group %s is not defined in pattern" % variable_match.group('varname'))
replacement = variable_match.group('varname')
try:
closingline = closingline.replace(variable_match.group(0), replacement)
except TypeError:
if replacement is None:
replacement = ""
closingline = closingline.replace(variable_match.group(0), str(replacement))
else:
break
else:
return (None, None)
closingline = closingline.rstrip()
return (indent, closingline)
def fortran_complete():
syntax_elements = [
SyntaxElement(re.compile(r'^\s*program\s+(?P<name>[a-zA-Z0-9_]+)'),
'end program ${name}' ),
SyntaxElement(re.compile(r'^\s*type\s+(?P<name>[a-zA-Z0-9_]+)'),
'end type ${name}' ),
SyntaxElement(re.compile(r'^\s*interface\s+'),
'end interface' ),
SyntaxElement(re.compile(r'^\s*module\s+(?P<name>[a-zA-Z0-9_]+)'),
'end module ${name}' ),
SyntaxElement(re.compile(r'^\s*subroutine\s+(?P<name>[a-zA-Z0-9_]+)'),
'end subroutine ${name}' ),
SyntaxElement(re.compile(r'^\s*\w*\s*function\s+(?P<name>[a-zA-Z0-9_]+)'),
'end function ${name}' ),
SyntaxElement(re.compile(r'^\s*((?P<name>([a-zA-Z0-9_]+))\s*:)?\s*if \s*\(.*\) \s*then'),
'end if ${name}' ),
SyntaxElement(re.compile(r'^\s*((?P<name>([a-zA-Z0-9_]+))\s*:)?\s*do'),
'end do ${name}' ),
SyntaxElement(re.compile(r'^\s*select case '),
'end select' )
]
cb = vim.current.buffer
line = vim.current.window.cursor[0] - 1
cline = cb[line]
for syntax_element in syntax_elements:
(indent, closingline) = syntax_element.match(cline)
if closingline is not None:
vim.command('s/$/\x0D\x0D/') # insert two lines
shiftwidth = int(vim.eval("&shiftwidth"))
cb[line+1] = indent + (" " * shiftwidth)
cb[line+2] = indent + closingline
vim.current.window.cursor = (line+2, 1)
EOF
nmap <F7> :python3 fortran_complete()<cr>A
imap <F7> ^[:python3 fortran_complete()<cr>A