Если вы не работаете в среде, где gnu make недоступен или плохо настроен (mingw), вам не понадобится Makefile
для монофайловых проектов. Они не являются обязательными в этом случае, и IMO больше хлопот, чем что-либо еще.
Компиляция лучше всего выполняется с:
:make %<
Таким образом, любые ошибки напрямую переходят к окнам быстрого исправления. Это повысит вашу производительность при поиске ошибок (:h quickfix
). Кроме того, независимо от того, используется ли ваш текущий файл на C, C ++, Fortran ... или на любом другом языке, распознаваемом по умолчанию конфигурацией gnumake, вам не нужно указывать компилятор, который вы хотите использовать, в зависимости от текущего типа файла. Если вы действительно хотите выбрать другой компилятор для C ++, например, вы можете использовать
:let $CXX ='clang++'
" $CC for C, and so on
А если вы хотите изменить параметры компиляции
:let $CXXFLAGS = '-std=c++17 -Wall -Werror'
" $CFLAGS for C, $LDLIBS, $LDFLAGS for the linker, and so on
Обратите внимание, что если у вас есть Makefile
, он будет автоматически использован.
Цепочка с исполнением
:!make %< && ./%<
действительно достаточно просто, чтобы соединить оба шага. Увы, у нас нет прямого эквивалента с :make
. Мы должны проанализировать список быстрых исправлений, чтобы увидеть, были ли какие-либо проблемы
Если filter(getqflist(), 'v:val.valid != 0')
не пусто, мы можем узнать, были ли обнаружены проблемы. Но это не говорит, являются ли они предупреждениями или ошибками. Мы можем получить полную информацию со следующим
" 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
Исходя из этого, мы можем решить остановиться только на ошибках или на ошибках и предупреждениях.
Дополнительные входы
С помощью filereadable()
мы можем знать, находится ли здесь входной файл.
Таким образом, оно становится:
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
Если вы хотите перенаправить результат в терминал:, на этот раз, к сожалению, перенаправление не может быть использовано с Vim (хотя он работает с nvim)
TL; DR
Окончательный код (учитывая предыдущую функцию для обнаружения ошибок и предупреждений) становится.
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>