文件自动执行插件

2021-03-28 20:52:12 +08:00
 chemzqm

coc.nvim 插件,放在 .vim/coc-extensions 目录下即可使用。

右侧打开窗口显示执行代码的结果,保存后自动重新执行。

stderr 和 stdout 出现顺序可能会错,暂时不支持 ansi 解析,可通过使用 strip-ansi 模块去掉。

const {Uri, commands, workspace, window, Mutex} = require('coc.nvim')
const path = require('path')

const programMap = {
  javascript: 'node',
  typescript: 'ts-node',
  python: 'python'
}
let global_id = 0

exports.activate = async context => {
  const {nvim, cwd} = workspace
  // bufnr => Task
  const taskMap = new Map()

  let statusItem = window.createStatusBarItem(0, {progress: true})
  context.subscriptions.push(statusItem)

  const executeFile = async (doc, create) => {
    let uri = doc.uri
    let relPath = path.relative(cwd, Uri.parse(uri).fsPath)
    let bufname = `__coc_execute_${doc.bufnr}__`
    let task = taskMap.get(doc.bufnr)
    if (task) {
      task.dispose()
      taskMap.delete(doc.bufnr)
    }
    statusItem.hide()
    let winnr = await nvim.call('bufwinnr', [bufname])
    if (winnr == -1 && !create) return
    if (winnr == -1) {
      nvim.pauseNotification()
      nvim.command(`belowright vs ${bufname}`)
      nvim.command(`setl buftype=nofile`)
      nvim.command(`setl conceallevel=0`)
      nvim.command(`setl norelativenumber`)
      await nvim.resumeNotification()
      winnr = await nvim.call('winnr', [])
      await nvim.command('wincmd p')
    } else {
      // clear buffer
      await nvim.command(`silent call deletebufline('${bufname}', 1, '$')`)
    }
    let bufId = await nvim.call('bufnr', [bufname])
    let buf = nvim.createBuffer(bufId)
    let t = workspace.createTask(`execute-${global_id}`)
    global_id = global_id + 1
    let cmd = programMap[doc.filetype]
    // start with options
    let succeed = await t.start({cwd, cmd, args: [relPath]})
    if (!succeed) {
      window.showErrorMessage(`Command failed to start: ${cmd} ${relPath}`)
      return
    }
    statusItem.text = `${cmd} ${relPath}`
    statusItem.show()
    taskMap.set(doc.bufnr, t)
    t.onExit(code => {
      statusItem.hide()
      taskMap.delete(doc.bufnr)
      if (code != 0) {
        window.showErrorMessage(`${cmd} exit with code: ${code}`)
      }
    })
    let empty = true
    let appendLines = async lines => {
      if (empty) {
        empty = false
        await buf.setLines(lines, {start: 0, end: -1, strictIndexing: false})
      } else {
        await nvim.call('appendbufline', [buf.id, '$', lines])
      }
    }
    let mutex = new Mutex()
    t.onStderr(async lines => {
      let replace = empty
      let release = await mutex.acquire()
      try {
        let len = await buf.length
        await appendLines(lines)
        await buf.highlightRanges('coc-execute', 'WarningMsg', [{
          start: {line: (replace ? len - 1 : len), character: 0},
          end: {line: len + lines.length, character: 0}
        }])
        if (workspace.isVim) nvim.command('redraw', true)
      } catch (e) {
        window.showErrorMessage(e.message)
      }
      release()
    })
    t.onStdout(async lines => {
      let release = await mutex.acquire()
      try {
        await appendLines(lines)
        if (workspace.isVim) nvim.command('redraw', true)
      } catch (e) {
        window.showErrorMessage(e.message)
      }
      release()
    })
  }

  const execute = async () => {
    let doc = await workspace.document
    let program = programMap[doc.filetype]
    if (!program) {
      window.showErrorMessage(`filetype not supported`)
      return
    }
    await executeFile(doc, true)
  }
  context.subscriptions.push(workspace.onDidSaveTextDocument(async e => {
    let doc = workspace.getDocument(e.uri)
    if (!taskMap.has(doc.bufnr)) return
    await executeFile(doc, false)
  }))

  context.subscriptions.push({
    dispose: () => {
      for (let task of taskMap.values()) {
        task.dispose()
      }
    }
  })

  context.subscriptions.push(
    commands.registerCommand('execute.currentFile', execute)
  )
}

仅供参考

2078 次点击
所在节点    Vim
3 条回复
IgniteWhite
2021-03-28 21:26:59 +08:00
给大佬点赞
chemzqm
2021-03-29 00:07:08 +08:00
多了一行 `if (!taskMap.has(doc.bufnr)) return`
yuuko
2021-03-29 17:20:37 +08:00
我这里

nvim.pauseNotification()
nvim.command(`belowright vs ${bufname}`)

要改成

await nvim.command(`belowright vs ${bufname}`)
nvim.pauseNotification()

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/765952

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX