1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-03 15:40:04 +08:00
SpaceVim/bundle/deoplete-go/rplugin/python3/deoplete/sources/deoplete_go/cgo.py

215 lines
6.9 KiB
Python
Raw Normal View History

import os
import re
from clang_index import Clang_Index
class cgo(object):
def get_inline_source(buffer):
# TODO(zchee): very slow. about 100ms
if 'import "C"' not in buffer:
return (0, "")
pos_import_c = list(buffer).index('import "C"')
c_inline = buffer[:pos_import_c]
if c_inline[len(c_inline) - 1] == "*/":
comment_start = next(
i
for i, v in zip(range(len(c_inline) - 1, 0, -1), reversed(c_inline))
if v == "/*"
)
c_inline = c_inline[comment_start + 1 : len(c_inline) - 1]
return (len(c_inline), "\n".join(c_inline))
def get_pkgconfig(packages):
out = []
pkgconfig = cgo.find_binary_path("pkg-config")
if pkgconfig != "":
for pkg in packages:
flag = os.popen(pkgconfig + " " + pkg + " --cflags --libs").read()
out += flag.rstrip().split(" ")
return out
def parse_candidates(result):
completion = {"dup": 1, "word": ""}
_type = ""
word = ""
placeholder = ""
sep = " "
for chunk in [x for x in result.string if x.spelling]:
chunk_spelling = chunk.spelling
# ignore inline fake main(void), and '_' prefix function
if chunk_spelling == "main" or chunk_spelling.find("_") == 0:
return completion
if chunk.isKindTypedText():
word += chunk_spelling
placeholder += chunk_spelling
elif chunk.isKindResultType():
_type += chunk_spelling
else:
placeholder += chunk_spelling
completion["word"] = word
completion["abbr"] = completion["info"] = placeholder + sep + _type
completion["kind"] = " ".join(
[
(
Clang_Index.kinds[result.cursorKind]
if (result.cursorKind in Clang_Index.kinds)
else str(result.cursorKind)
)
]
)
return completion
def complete(index, cache, cgo_options, line_count, source):
cgo_pattern = r"#cgo (\S+): (.+)"
flags = set()
for key, value in re.findall(cgo_pattern, source):
if key == "pkg-config":
for flag in cgo.get_pkgconfig(value.split()):
flags.add(flag)
else:
if "${SRCDIR}" in key:
key = key.replace("${SRCDIR}", "./")
flags.add("%s=%s" % (key, value))
cgo_flags = ["-std", cgo_options["std"]] + list(flags)
fname = "cgo_inline.c"
main = """
int main(void) {
}
"""
template = source + main
files = [(fname, template)]
# clang.TranslationUnit
# PARSE_NONE = 0
# PARSE_DETAILED_PROCESSING_RECORD = 1
# PARSE_INCOMPLETE = 2
# PARSE_PRECOMPILED_PREAMBLE = 4
# PARSE_CACHE_COMPLETION_RESULTS = 8
# PARSE_SKIP_FUNCTION_BODIES = 64
# PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION = 128
options = 15
# Index.parse(path, args=None, unsaved_files=None, options = 0)
tu = index.parse(fname, cgo_flags, unsaved_files=files, options=options)
# TranslationUnit.codeComplete(path, line, column, ...)
cr = tu.codeComplete(
fname,
(line_count + 2),
1,
unsaved_files=files,
include_macros=True,
include_code_patterns=True,
include_brief_comments=False,
)
if cgo_options["sort_algo"] == "priority":
results = sorted(cr.results, key=cgo.get_priority)
elif cgo_options["sort_algo"] == "alphabetical":
results = sorted(cr.results, key=cgo.get_abbrevation)
else:
results = cr.results
# Go string to C string
# The C string is allocated in the C heap using malloc.
# It is the caller's responsibility to arrange for it to be
# freed, such as by calling C.free (be sure to include stdlib.h
# if C.free is needed).
# func C.CString(string) *C.char
#
# Go []byte slice to C array
# The C array is allocated in the C heap using malloc.
# It is the caller's responsibility to arrange for it to be
# freed, such as by calling C.free (be sure to include stdlib.h
# if C.free is needed).
# func C.CBytes([]byte) unsafe.Pointer
#
# C string to Go string
# func C.GoString(*C.char) string
#
# C data with explicit length to Go string
# func C.GoStringN(*C.char, C.int) string
#
# C data with explicit length to Go []byte
# func C.GoBytes(unsafe.Pointer, C.int) []byte
cache[source] = [
{
"word": "CString",
"abbr": "CString(string) *C.char",
"info": "CString(string) *C.char",
"kind": "function",
"dup": 1,
},
{
"word": "CBytes",
"abbr": "CBytes([]byte) unsafe.Pointer",
"info": "CBytes([]byte) unsafe.Pointer",
"kind": "function",
"dup": 1,
},
{
"word": "GoString",
"abbr": "GoString(*C.char) string",
"info": "GoString(*C.char) string",
"kind": "function",
"dup": 1,
},
{
"word": "GoStringN",
"abbr": "GoStringN(*C.char, C.int) string",
"info": "GoStringN(*C.char, C.int) string",
"kind": "function",
"dup": 1,
},
{
"word": "GoBytes",
"abbr": "GoBytes(unsafe.Pointer, C.int) []byte",
"info": "GoBytes(unsafe.Pointer, C.int) []byte",
"kind": "function",
"dup": 1,
},
]
cache[source] += list(map(cgo.parse_candidates, results))
return cache[source]
def get_priority(x):
return x.string.priority
def get_abbr(strings):
for chunks in strings:
if chunks.isKindTypedText():
return chunks.spelling
return ""
def get_abbrevation(x):
return cgo.get_abbr(x.string).lower()
def find_binary_path(cmd):
def is_exec(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(cmd)
if fpath:
if is_exec(cmd):
return cmd
else:
for path in os.environ["PATH"].split(os.pathsep):
path = path.strip('"')
binary = os.path.join(path, cmd)
if is_exec(binary):
return binary
return ""