| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- # encoding=utf-8
- import vim
- import re
- import sys
- import os.path
- import argparse
- import shlex
- from subprocess import Popen, PIPE
- from itertools import chain
- from vim_pandoc.utils import plugin_enabled_modules, ensure_string
- from vim_pandoc.bib.vim_completer import find_bibfiles
- from vim_pandoc.helpparser import PandocInfo
- class PandocCommand(object):
- def __init__(self):
- self.pandoc_info = PandocInfo(vim.vars["pandoc#command#path"])
- self.formats_table = {}
- self.build_formats_table()
- self._output_file_path = None
- self._run_command = None
- self._out = None
- self._python_executable = None
- def build_formats_table(self):
- for i in self.pandoc_info.output_formats:
- if i in ("asciidoc", "plain"):
- self.formats_table[i] = "txt"
- elif i in ("beamer", "pdf"):
- self.formats_table[i] = "pdf"
- elif i in ("dzslides", "html", "html5", "mediawiki", "revealjs", "s5", "slideous", "slidy"):
- self.formats_table[i] = "html"
- elif i in ("markdown", "gfm", "markdown_github", "markdown_mmd", "markdown_phpextra", "markdown_strict"):
- self.formats_table[i] = "md"
- elif i in ("odt", "opendocument"):
- self.formats_table[i] = "odt"
- elif i == "native":
- self.formats_table[i] = "hs"
- elif i == "texinfo":
- self.formats_table[i] = "info"
- elif i == "latex":
- self.formats_table[i] = "tex"
- else:
- self.formats_table[i] = i
- if "latex" in self.formats_table or "beamer" in self.formats_table and "pdf" not in self.formats_table:
- self.formats_table["pdf"] = "pdf"
- def __call__(self, args, should_open):
- largs = shlex.split(args)
- if largs == [] or largs[0].startswith('-'):
- largs = ['html'] + largs # make sure we pass an output format
- p = self.pandoc_info.build_argument_parser()
- c_vars = vars(p.parse_args(largs))
- # Infer arguments from vim environment
- # a) bibliographies
- if 'bibliographies' in plugin_enabled_modules():
- local_bibs = vim.eval('b:pandoc_biblio_bibs')
- found_bibs = find_bibfiles()
- if local_bibs or found_bibs and not c_vars['bibliography']:
- c_vars['bibliography'] = []
- if local_bibs:
- c_vars['bibliography'].extend(local_bibs)
- if found_bibs:
- c_vars['bibliography'].extend(found_bibs)
- # Now, we must determine what are our input and output files
- # a) First, let's see what is the desired output format...
- output_format = c_vars['output_format'] \
- if self.pandoc_info.is_valid_output_format(c_vars['output_format']) \
- or c_vars['output_format'] == 'pdf' \
- else "html"
- # overwrite --to with this value
- # 'pdf' is not a valid output format, we pass it to -o instead)
- if output_format != 'pdf':
- c_vars['to'] = output_format
- else:
- c_vars['to'] = 'latex'
- if output_format == 'pdf':
- # pdf engine
- if self.pandoc_info.version >= '2':
- engine_option = 'pdf_engine'
- else:
- engine_option = 'latex_engine'
- if not c_vars[engine_option]:
- try: # try a buffer local engine
- engine_var = ensure_string(vim.current.buffer.vars['pandoc_command_latex_engine'])
- except: # use te global value
- engine_var = ensure_string(vim.vars['pandoc#command#latex_engine'])
- c_vars[engine_option] = str(engine_var)
- if not c_vars['output']:
- self._output_file_path = vim.eval('expand("%:r")') + '.' \
- + self.formats_table[re.split("[-+]", output_format)[0]]
- c_vars['output'] = self._output_file_path
- else:
- self._output_file_path = os.path.expanduser(c_vars['output'][0])
- input_arg = '"' + vim.eval('expand("%")') + '"'
- # Now, we reconstruct the pandoc call
- arglist = []
- arglist.append(ensure_string(vim.vars['pandoc#compiler#command']))
- arglist.append(ensure_string(vim.vars['pandoc#compiler#arguments']))
- # Only consider enabled flags and arguments with values
- extra_arg_vars_keys = [k for k in c_vars.keys() if c_vars[k] and k != 'output_format']
- for var in extra_arg_vars_keys:
- real_var = var.replace("_", "-")
- val = c_vars[var]
- if type(val) == list and len(val) > 1: # multiple values, repeat keys
- for vv in val:
- if type(vv) == list and type(vv[0]) == list:
- vv = vv[0][0]
- elif type(vv) == list:
- vv = vv[0]
- elif type(val) == bool:
- vv = None
- if vv:
- vv = os.path.expanduser(vv)
- arglist.append("--" + real_var + '="' + str(vv) + '"')
- else:
- arglist.append("--" + real_var)
- else:
- if type(val) == list and type(val[0]) == list:
- val = val[0][0]
- elif type(val) == list:
- val = val[0]
- elif type(val) == bool:
- val = None
- if val:
- val = os.path.expanduser(val)
- arglist.append('--' + real_var + '="' + str(val) + '"')
- else:
- arglist.append('--' + real_var)
- arglist.append(input_arg)
- self._run_command = " ".join(arglist)
- # execute
- self.execute(should_open)
- def python_executable(self):
- if self._python_executable is None:
- if vim.eval("executable('python')") == '1':
- self._python_executable = 'python'
- elif vim.eval("executable('python3')") == '1':
- self._python_executable = 'python3'
- return self._python_executable
- def execute(self, should_open):
- with open("pandoc.out", 'w') as tmp:
- # for nvim
- if vim.eval("has('nvim')") == '1':
- try:
- should_open_s = str(int(should_open))
- except:
- should_open_s = '0'
- if int(vim.eval("bufloaded('pandoc-execute')")):
- wnr = vim.eval("bufwinnr('pandoc-execute')")
- vim.command(wnr + "wincmd c")
- vim.command(wnr + "put='Running pandoc...\n'")
- vim.command("botright 7new pandoc-execute")
- vim.command("setlocal buftype=nofile")
- vim.command("setlocal bufhidden=wipe")
- vim.command("setlocal nobuflisted")
- vim.command("map <buffer> q <Esc>:close<Enter>")
- vim.command("call termopen(" + \
- "['"+ "','".join(shlex.split(self._run_command)) + "'], " + \
- " extend({'should_open': '" + should_open_s + "'}," +\
- " {'on_exit': 'pandoc#command#JobHandler'," + \
- "'on_stdout': 'pandoc#command#JobHandler'," + \
- "'on_stderr': 'pandoc#command#JobHandler'}))")
- vim.command("file pandoc-execute")
- vim.command("normal G")
- vim.command("wincmd p")
- # for vim versions with clientserver support
- elif vim.eval("has('clientserver')") == '1' and \
- vim.eval("v:servername") != "" and \
- self.python_executable() is not None:
- async_runner = '"' + os.path.join(os.path.dirname(__file__), "async.py") + '"'
- servername_arg = "--servername=" + vim.eval("v:servername")
- open_arg = "--open" if should_open else "--noopen"
- async_command = " ".join([self.python_executable(), async_runner, servername_arg, open_arg, self._run_command])
- try:
- Popen(shlex.split(async_command), stdout=tmp, stderr=tmp)
- except:
- vim.command('echoe "vim-pandoc: could not execute pandoc asynchronously"')
- else:
- try: # fallback to synchronous execution
- com = Popen(shlex.split(self._run_command), stdout=tmp, stderr=tmp)
- com.wait()
- except:
- vim.command('echoe "vim-pandoc: could not execute pandoc"')
- return
- self.on_done(should_open, com.returncode)
- def on_done(self, should_open, returncode):
- if self._run_command and self._output_file_path:
- vim.command("echohl Statement")
- vim.command("echom strftime('%Y%m%d %T') . ' vim-pandoc:ran " + self._run_command + "'")
- vim.command("echohl None")
- if vim.eval("g:pandoc#command#use_message_buffers") == '1' \
- and returncode not in ('0', 0):
- vim.command("let split = &splitbelow")
- vim.command("set splitbelow")
- vim.command("5new pandoc\ output")
- vim.command("let &splitbelow = split")
- vim.command("setlocal wrap")
- vim.command("setlocal linebreak")
- vim.current.buffer[0] = "# Press q to close this"
- vim.current.buffer.append("> " + self._run_command)
- vim.command("normal! G")
- if vim.eval('filereadable("pandoc.out")') == '1':
- vim.command("silent r pandoc.out")
- vim.command("setlocal buftype=nofile")
- vim.command("setlocal nobuflisted")
- # pressing q on the buffer will delete it
- vim.command("map <buffer> q :bwipeout<cr>")
- # we will highlight some elements in the buffer
- vim.command("syn match PandocOutputMarks /^>>/")
- vim.command("syn match PandocCommand /^>.*$/hs=s+1")
- vim.command("syn match PandocInstructions /^#.*$/")
- vim.command("hi! link PandocOutputMarks Operator")
- vim.command("hi! link PandocCommand Debug")
- vim.command("hi! link PandocInstructions Comment")
- # under windows, pandoc.out is not closed by async.py in time sometimes,
- # so we wait a bit
- if sys.platform.startswith("win"):
- from time import sleep
- sleep(1)
- if os.path.exists("pandoc.out"):
- os.remove("pandoc.out")
- # open file if needed
- # nvim's python host doesn't change the directory the same way vim does
- try:
- if vim.eval('has("nvim")') == '1':
- os.chdir(vim.eval('getcwd()'))
- except:
- pass
- if vim.eval("g:pandoc#command#prefer_pdf") == "1":
- maybe_pdf = os.path.splitext(self._output_file_path)[0] + ".pdf"
- if os.path.splitext(self._output_file_path)[1] in [".tex", "*.latex"] \
- and os.path.exists(maybe_pdf):
- self._output_file_path = maybe_pdf
- if os.path.exists(os.path.abspath(self._output_file_path)) and should_open:
- # if g:pandoc#command#custom_open is defined and is a valid funcref
- if vim.eval("g:pandoc#command#custom_open") != "" \
- and vim.eval("exists('*"+vim.eval("g:pandoc#command#custom_open")+"')") == '1':
- custom_command = vim.eval(vim.eval("g:pandoc#command#custom_open") \
- + "('"+self._output_file_path+"')")
- Popen(shlex.split(custom_command))
- # otherwise use platform defaults:
- else:
- if sys.platform == "darwin" or sys.platform.startswith("linux"):
- if sys.platform == "darwin":
- open_command = "open" #OSX
- elif sys.platform.startswith("linux"):
- open_command = "xdg-open" # freedesktop/linux
- with open(os.devnull, 'wb') as fnull:
- Popen([open_command, self._output_file_path], stderr=fnull)
- elif sys.platform.startswith("win"):
- Popen('cmd /c "start ' + self._output_file_path + '"')
- # we reset this
- self._output_file_path = None
- self._run_command = None
- vim.command("redraw")
- if returncode in ("0", 0):
- vim.command("echohl Statement")
- vim.command("echom 'vim-pandoc:ran successfully.'")
- vim.command("echohl None")
- pandoc = PandocCommand()
|