mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-03 09:10:04 +08:00
245 lines
7.2 KiB
VimL
245 lines
7.2 KiB
VimL
"=============================================================================
|
|
" xmake.vim --- xmake support for spacevim
|
|
" Copyright (c) 2016-2023 Wang Shidong & Contributors
|
|
" Author: Wang Shidong < wsdjeg@outlook.com >
|
|
" Original Author: luzhlon
|
|
" URL: https://spacevim.org
|
|
" License: GPLv3
|
|
"=============================================================================
|
|
" This file is based on:
|
|
" https://github.com/luzhlon/xmake.vim/tree/5b20e97f5d0b063a97be23451c730d0278eef927
|
|
|
|
""
|
|
" @section Introduction, intro
|
|
" @library
|
|
" xmake.vim is a plugin for using xmake in vim and neovim.
|
|
" This plugin requires SpaceVim API and |job| support.
|
|
|
|
" load the spacevim APIs:
|
|
let s:JOB = SpaceVim#api#import('job')
|
|
let s:NOTI = SpaceVim#api#import('notify')
|
|
|
|
let s:job = 0 " subprocess of xmake
|
|
let s:xmake_need_to_run = 0 " run this command after building successfully
|
|
let s:target = '' " target to build, build ALL if empty
|
|
let s:cb_cexpr = {j,d,s->vim#cadde(join(d, "\n"))}
|
|
|
|
|
|
function! s:xmake_stdout(id, data, event) abort
|
|
|
|
endfunction
|
|
|
|
function! s:xmake_stderr(id, data, event) abort
|
|
|
|
endfunction
|
|
|
|
function! s:xmake_exit(id, data, event) abort
|
|
if a:data
|
|
" copen
|
|
" if build failed, we need to display the error message
|
|
call s:NOTI.notify('build failed', 'Error')
|
|
call s:NOTI.notify('xmake returned ' . a:data, 'Error')
|
|
else
|
|
call s:NOTI.notify('build success' . s:target, 'MoreMsg')
|
|
if s:xmake_need_to_run
|
|
let t = get(get(g:xmproj['targets'], s:target, {}), 'targetfile')
|
|
if empty(t)
|
|
call s:NOTI.notify('Target not exists:' . s:target, 'Error')
|
|
else
|
|
call SpaceVim#plugins#runner#open(empty(s:target) ? 'xmake run': t)
|
|
endif
|
|
endif
|
|
endif
|
|
endfunction
|
|
" Get the bufnr about a target's sourcefiles and headerfiles
|
|
func! s:targetbufs(target)
|
|
let nrs = {}
|
|
for i in a:target['sourcefiles'] + a:target['headerfiles']
|
|
let n = bufnr(i)
|
|
if n > 0 && getbufvar(n, '&mod')
|
|
let nrs[n] = 1
|
|
endif
|
|
endfor
|
|
return nrs
|
|
endfunction
|
|
|
|
" Get the bufnrs to save
|
|
fun! s:buf2save()
|
|
if empty(s:target)
|
|
" Save all target's file
|
|
let nrs = {}
|
|
for tf in values(g:xmproj['targets'])
|
|
call extend(nrs, s:targetbufs(tf))
|
|
endfor
|
|
else
|
|
" Save s:target's file
|
|
let nrs = s:targetbufs(g:xmproj['targets'][s:target])
|
|
endif
|
|
return keys(nrs)
|
|
endfunction
|
|
" Save the file before building
|
|
fun! s:savefiles()
|
|
let n = bufnr('%') " save current bufnr
|
|
let bufnrs = s:buf2save()
|
|
let xnr = bufnr('xmake.lua')
|
|
if xnr > 0
|
|
call add(bufnrs, xnr)
|
|
endif
|
|
for nr in bufnrs " traverse project's files, and save them
|
|
sil! exe nr . 'bufdo!' 'up'
|
|
endfor
|
|
" switch to original buffer
|
|
exe 'b!' n
|
|
endfunction
|
|
|
|
" If exists a xmake subprocess
|
|
fun! s:isRunning()
|
|
if !empty(s:job) && s:JOB.status(s:job) == 'run'
|
|
call s:NOTI.notify('a xmake task is running')
|
|
return 1
|
|
endif
|
|
endfunction
|
|
" If loaded the xmake's configuration
|
|
fun! s:notLoaded()
|
|
if exists('g:xmproj')
|
|
return 0
|
|
endif
|
|
call s:NOTI.notify('No xmake-project loaded')
|
|
return 1
|
|
endfunction
|
|
" Building by xmake
|
|
fun! xmake#buildrun(...)
|
|
if s:notLoaded() | return | endif
|
|
if s:isRunning() | return | endif
|
|
" call s:savefiles() " save files about the target to build
|
|
wall
|
|
let s:xmake_need_to_run = a:0 && a:1
|
|
let color = $COLORTERM
|
|
cexpr ''
|
|
let cmd = empty(s:target) ? 'xmake': ['xmake', 'build', s:target]
|
|
if has_key(g:xmproj, 'compiler')
|
|
exe 'compiler' g:xmproj['compiler']
|
|
endif
|
|
let s:job = s:JOB.start(cmd, {
|
|
\ 'on_stdout': function('s:xmake_stdout'),
|
|
\ 'on_stderr': function('s:xmake_stderr'),
|
|
\ 'on_exit': function('s:xmake_exit'),
|
|
\ 'env' : {'COLORTERM' : 'nocolor'}
|
|
\ })
|
|
endfunction
|
|
" Interpret XMake command
|
|
fun! xmake#xmake(...)
|
|
let argv = filter(copy(a:000), {i,v->v!=''})
|
|
let argc = len(argv)
|
|
if !argc " building all targets without running
|
|
let s:target = ''
|
|
call xmake#buildrun()
|
|
elseif argv[0] == 'run' || argv[0] == 'r' " building && running
|
|
if argc > 1 | let s:target = argv[1] | endif
|
|
call xmake#buildrun(1)
|
|
elseif argv[0] == 'build' " building specific target
|
|
if argc > 1 | let s:target = argv[1] | endif
|
|
call xmake#buildrun()
|
|
else " else xmake's commands
|
|
if s:isRunning() | return | endif
|
|
let s:job = s:JOB.start(['xmake'] + argv, {
|
|
\ 'on_stdout': function('s:xmake_stdout'),
|
|
\ 'on_stderr': function('s:xmake_stderr'),
|
|
\ 'on_exit': function('s:xmake_exit'),
|
|
\ 'env' : {'COLORTERM' : 'nocolor'}
|
|
\ })
|
|
endif
|
|
endfunction
|
|
|
|
fun! s:onload(...)
|
|
" Check the fields
|
|
for t in values(g:xmproj['targets'])
|
|
if empty(t.headerfiles)
|
|
let t.headerfiles = []
|
|
endif
|
|
if empty(t.sourcefiles)
|
|
let t.sourcefiles = []
|
|
endif
|
|
endfor
|
|
" Support SpaceVim's tabmanager
|
|
call s:NOTI.notify('XMake-Project loaded successfully', 'MoreMsg')
|
|
let config = g:xmproj.config
|
|
let t:_spacevim_tab_name = join(filter([g:xmproj['name'], get(config, 'mode', ''), get(config, 'arch', '')], '!empty(v:val)'), ' - ')
|
|
call xmake#log#info('change the project name to:' . t:_spacevim_tab_name)
|
|
" Find compiler
|
|
let cc = get(g:xmproj.config, 'cc', '')
|
|
let cxx = get(g:xmproj.config, 'cxx', '')
|
|
let compiler = ''
|
|
if !empty(cxx)
|
|
let compiler = cxx
|
|
elseif !empty(cc)
|
|
let compiler = cc
|
|
endif
|
|
if !empty(compiler)
|
|
let t = {'cl.exe': 'msvc', 'gcc': 'gcc'}
|
|
let g:xmproj.compiler = t[compiler]
|
|
endif
|
|
endfunction
|
|
|
|
augroup xmake_autoload
|
|
autocmd!
|
|
au User XMakeLoaded call <SID>onload()
|
|
augroup END
|
|
|
|
|
|
let s:path = expand('<sfile>:p:h')
|
|
let s:xmake_load_stdout_cache = []
|
|
let s:xmake_load_tempname = ''
|
|
function! s:xmake_load_stdout(id, data, event) abort
|
|
call add(s:xmake_load_stdout_cache, a:data)
|
|
endfunction
|
|
|
|
function! s:xmake_load_stderr(id, data, event) abort
|
|
for line in a:data
|
|
let s:NOTI.notify_max_width = max([strwidth(line) + 5, s:NOTI.notify_max_width])
|
|
call s:NOTI.notify(line, 'WarningMsg')
|
|
endfor
|
|
endfunction
|
|
|
|
function! s:xmake_load_exit(id, data, event) abort
|
|
call xmake#log#info('LoadXCfg entered.')
|
|
if a:data
|
|
call s:NOTI.notify('XMake-Project loaded unsuccessfully.')
|
|
call s:NOTI.notify('xmake returned ' . a:data)
|
|
else
|
|
let l = ''
|
|
try
|
|
let l = readfile(s:xmake_load_tempname)
|
|
let g:xmproj = json_decode(l[0])
|
|
do User XMakeLoaded
|
|
catch
|
|
call xmake#log#debug('xmake_load_tempname is: ' . s:xmake_load_tempname)
|
|
call xmake#log#debug('failed to paser s:xmake_load_tempname')
|
|
call xmake#log#debug(' exception: ' . v:exception)
|
|
call xmake#log#debug(' throwpoint: ' . v:throwpoint)
|
|
endtry
|
|
endif
|
|
endfunction
|
|
|
|
fun! xmake#load()
|
|
let s:xmake_load_stdout_cache = []
|
|
let s:xmake_load_tempname = tempname()
|
|
let cmdline = ['xmake', 'lua', s:path . '/spy.lua', '-o', s:xmake_load_tempname, 'project']
|
|
call xmake#log#info('cmdline is:' . string(cmdline))
|
|
let jobid = s:JOB.start(cmdline, {
|
|
\ 'on_stdout' : function('s:xmake_load_stdout'),
|
|
\ 'on_stderr' : function('s:xmake_load_stderr'),
|
|
\ 'on_exit' : function('s:xmake_load_exit')
|
|
\ }
|
|
\ )
|
|
endfunction
|
|
|
|
|
|
function! xmake#on_project_changed() abort
|
|
if filereadable('xmake.lua')
|
|
call xmake#load()
|
|
endif
|
|
endfunction
|
|
|
|
" vim:set et sw=2 cc=80:
|