Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
545 views
in Technique[技术] by (71.8m points)

vim mapping for running c++ with optional input file

I am configuring vimrc file for competitive programming in c++.

autocmd filetype cpp nnoremap <F5> :w <CR> 
                                   :!g++ -o %:r % <CR> :!./%:r < input.txt <CR>

The following mapping is when I press F5, it saves, compiles (%:r is filename without .cpp), and runs with input.txt file.

However not every cpp file has input.txt, so I want to pipe input.txt only when input.txt exists in the current directory.

To sum up, what is the best way of checking files during the mapping?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Unless you're working in an environment where gnu make is not available, or poorly configured (mingw), you won't need any Makefile for mono-file projects. They are not mandatory in that case, and IMO more of an hassle than anything else.

Compilation is best done with:

:make %<

This way any errors directly go to the quickfix windows. This will improve your productivity to locate errors (:h quickfix). Also, whether your current file is in C, C++, Fortran... or any language recognized by default gnumake configuration, you don't have to specify the compiler you wish to use depending on the current filetype. If you really want to select another compiler for C++ for instance, you can use

:let $CXX ='clang++'
" $CC for C, and so on

And if you want to change your compilation options

:let $CXXFLAGS = '-std=c++17 -Wall -Werror'
" $CFLAGS for C, $LDLIBS, $LDFLAGS for the linker, and so on

Note also that if you have a Makefile, it'll be automatically used.

Chaining with the execution

:!make %< && ./%< indeed is simple enough to chain both steps. Alas, we don't have the direct equivalent with :make. We have to analyse the quickfix list to see if there were any issue

If filter(getqflist(), 'v:val.valid != 0') is not empty we can know whether problems have been detected. But it doesn't tell whether they are warnings or errors. We can have the complete information with the following

" From my build-tools-wrapper plugin
function! lh#btw#build#_get_metrics() abort
  let qf = getqflist()
  let recognized = filter(qf, 'get(v:val, "valid", 1)')
  " TODO: support other locales, see lh#po#context().tranlate()
  let errors   = filter(copy(recognized), 'v:val.type == "E" || v:val.text =~ "\v^ *(error|erreur)"')
  let warnings = filter(copy(recognized), 'v:val.type == "W" || v:val.text =~ "\v^ *(warning|attention)"')
  let res = { 'all': len(qf), 'errors': len(errors), 'warnings': len(warnings) }
  return res
endfunction

From this we can decide to stop just on errors, or on errors and warnings.

Optional inputs

With filereadable() we can know whether the input file is here.

It thus becomes:

let exec_line = '!./' . expand('%<') " we could also use the complete path instead
let input = expand('%:p:h')/.'input.txt'
if filereadable(input)
    let exec_line .= ' < ' . input
endif
exe exec_line

If you want to redirect the result in a :terminal, this time unfortunately, redirection cannot be used with Vim (it works with nvim though)

TL;DR

The final code (given the previous function to detect errors & warnings) becomes.

function s:build_and_run(file) abort
  let tgt  = fnamemodify(a:file, ':r')
  " to make sure the buffer is saved
  exe 'update ' . a:file
  exe 'make ' . tgt
  if lh#btw#build#_get_metrics().errors
    echom "Error detected, execution aborted"
    copen
    return
  endif

  let path = fnamemodify(a:file, ':p:h')
  let exec_line = '!./' . tgt
  let input = path.'/input.txt'
  if filereadable(input)
    let exec_line .= ' < ' . input
  endif
  exe exec_line
endfunction

nnoremap μ :<C-U>call <sid>build_and_run(expand('%'))<cr>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...