aboutsummaryrefslogtreecommitdiffstats
path: root/python/vhdl_langserver/workspace.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/vhdl_langserver/workspace.py')
-rw-r--r--python/vhdl_langserver/workspace.py155
1 files changed, 96 insertions, 59 deletions
diff --git a/python/vhdl_langserver/workspace.py b/python/vhdl_langserver/workspace.py
index a2cf9db4b..9d61225ee 100644
--- a/python/vhdl_langserver/workspace.py
+++ b/python/vhdl_langserver/workspace.py
@@ -24,6 +24,7 @@ log = logging.getLogger(__name__)
class ProjectError(Exception):
"Exception raised in case of unrecoverable error in the project file."
+
def __init__(self, msg):
super().__init__()
self.msg = msg
@@ -34,13 +35,13 @@ class Workspace(object):
self._root_uri = root_uri
self._server = server
self._root_path = lsp.path_from_uri(self._root_uri)
- self._docs = {} # uri -> doc
- self._fe_map = {} # fe -> doc
+ self._docs = {} # uri -> doc
+ self._fe_map = {} # fe -> doc
self._prj = {}
self._last_linted_doc = None
errorout_memory.Install_Handler()
libghdl.thin.flags.Flag_Elocations.value = True
- #thin.Flags.Verbose.value = True
+ # thin.Flags.Verbose.value = True
# We do analysis even in case of errors.
libghdl.thin.vhdl.parse.Flag_Parse_Parenthesis.value = True
# Force analysis to get more feedback + navigation even in case
@@ -52,7 +53,7 @@ class Workspace(object):
self.read_project()
self.set_options_from_project()
libghdl.analyze_init()
- self._diags_set = set() # Documents with at least one diagnostic.
+ self._diags_set = set() # Documents with at least one diagnostic.
self.read_files_from_project()
self.gather_diagnostics(None)
@@ -89,7 +90,9 @@ class Workspace(object):
path = lsp.path_from_uri(doc_uri)
if source is None:
source = open(path).read()
- sfe = document.Document.load(source, os.path.dirname(path), os.path.basename(path))
+ sfe = document.Document.load(
+ source, os.path.dirname(path), os.path.basename(path)
+ )
return self._create_document(doc_uri, sfe)
def get_or_create_document(self, doc_uri):
@@ -143,14 +146,14 @@ class Workspace(object):
fd.close()
except OSError as err:
self._server.show_message(
- lsp.MessageType.Error,
- "cannot load {}: {}".format(name, err.strerror))
+ lsp.MessageType.Error, "cannot load {}: {}".format(name, err.strerror)
+ )
return
doc = self.create_document_from_sfe(sfe, absname)
doc.parse_document()
def read_project(self):
- prj_file = os.path.join(self.root_path, 'hdl-prj.json')
+ prj_file = os.path.join(self.root_path, "hdl-prj.json")
if not os.path.exists(prj_file):
log.info("project file %s does not exist", prj_file)
return
@@ -159,7 +162,8 @@ class Workspace(object):
except OSError as err:
self._server.show_message(
lsp.MessageType.Error,
- "cannot open project file {}: {}".format(prj_file, err.strerror))
+ "cannot open project file {}: {}".format(prj_file, err.strerror),
+ )
return
log.info("reading project file %s", prj_file)
try:
@@ -169,7 +173,9 @@ class Workspace(object):
self._server.show_message(
lsp.MessageType.Error,
"json error in project file {}:{}:{}".format(
- prj_file, e.lineno, e.colno))
+ prj_file, e.lineno, e.colno
+ ),
+ )
f.close()
def set_options_from_project(self):
@@ -178,43 +184,48 @@ class Workspace(object):
return
if not isinstance(self._prj, dict):
raise ProjectError("project file is not a dictionnary")
- opts = self._prj.get('options', None)
+ opts = self._prj.get("options", None)
if opts is None:
return
if not isinstance(opts, dict):
raise ProjectError("'options' is not a dictionnary")
- ghdl_opts = opts.get('ghdl_analysis', None)
+ ghdl_opts = opts.get("ghdl_analysis", None)
if ghdl_opts is None:
return
log.info("Using options: %s", ghdl_opts)
for opt in ghdl_opts:
- if not libghdl.set_option(opt.encode('utf-8')):
- self._server.show_message(lsp.MessageType.Error,
- "error with option: {}".format(opt))
+ if not libghdl.set_option(opt.encode("utf-8")):
+ self._server.show_message(
+ lsp.MessageType.Error, "error with option: {}".format(opt)
+ )
except ProjectError as e:
- self._server.show_message(lsp.MessageType.Error,
- "error in project file: {}".format(e.msg))
+ self._server.show_message(
+ lsp.MessageType.Error, "error in project file: {}".format(e.msg)
+ )
def read_files_from_project(self):
try:
- files = self._prj.get('files', [])
+ files = self._prj.get("files", [])
if not isinstance(files, list):
raise ProjectError("'files' is not a list")
for f in files:
if not isinstance(f, dict):
raise ProjectError("an element of 'files' is not a dict")
- name = f.get('file')
+ name = f.get("file")
if not isinstance(name, str):
raise ProjectError("a 'file' is not a string")
- lang = f.get('language', 'vhdl')
- if lang == 'vhdl':
+ lang = f.get("language", "vhdl")
+ if lang == "vhdl":
self.add_vhdl_file(name)
except ProjectError as e:
- self._server.show_message(lsp.MessageType.Error,
- "error in project file: {}".format(e.msg))
+ self._server.show_message(
+ lsp.MessageType.Error, "error in project file: {}".format(e.msg)
+ )
def get_configuration(self):
- self._server.configuration([{'scopeUri': '', 'section': 'vhdl.maxNumberOfProblems'}])
+ self._server.configuration(
+ [{"scopeUri": "", "section": "vhdl.maxNumberOfProblems"}]
+ )
def gather_diagnostics(self, doc):
# Gather messages (per file)
@@ -222,15 +233,14 @@ class Workspace(object):
diags = {}
diag = {}
for i in range(nbr_msgs):
- hdr = errorout_memory.Get_Error_Record(i+1)
- msg = errorout_memory.Get_Error_Message(i+1).decode('utf-8')
+ hdr = errorout_memory.Get_Error_Record(i + 1)
+ msg = errorout_memory.Get_Error_Message(i + 1).decode("utf-8")
if hdr.file == 0:
# Possible for error limit reached.
continue
err_range = {
- 'start': {'line': hdr.line - 1, 'character': hdr.offset},
- 'end': {'line': hdr.line - 1,
- 'character': hdr.offset + hdr.length},
+ "start": {"line": hdr.line - 1, "character": hdr.offset},
+ "end": {"line": hdr.line - 1, "character": hdr.offset + hdr.length},
}
if hdr.group <= errorout_memory.Msg_Main:
if hdr.id <= errorout.Msgid.Msgid_Note:
@@ -239,12 +249,14 @@ class Workspace(object):
severity = lsp.DiagnosticSeverity.Warning
else:
severity = lsp.DiagnosticSeverity.Error
- diag = {'source': 'ghdl',
- 'range': err_range,
- 'message': msg,
- 'severity': severity}
+ diag = {
+ "source": "ghdl",
+ "range": err_range,
+ "message": msg,
+ "severity": severity,
+ }
if hdr.group == errorout_memory.Msg_Main:
- diag['relatedInformation'] = []
+ diag["relatedInformation"] = []
fdiag = diags.get(hdr.file, None)
if fdiag is None:
diags[hdr.file] = [diag]
@@ -254,9 +266,12 @@ class Workspace(object):
assert diag
if True:
doc = self.sfe_to_document(hdr.file)
- diag['relatedInformation'].append(
- {'location': {'uri': doc.uri, 'range': err_range},
- 'message': msg})
+ diag["relatedInformation"].append(
+ {
+ "location": {"uri": doc.uri, "range": err_range},
+ "message": msg,
+ }
+ )
errorout_memory.Clear_Errors()
# Publish diagnostics
for sfe, diag in diags.items():
@@ -275,7 +290,9 @@ class Workspace(object):
# Avoid infinite recursion
antideps[unit] = None
for un in udeps:
- log.debug("obsolete %d %s", un, pyutils.name_image(nodes.Get_Identifier(un)))
+ log.debug(
+ "obsolete %d %s", un, pyutils.name_image(nodes.Get_Identifier(un))
+ )
# Recurse
self.obsolete_dependent_units(un, antideps)
if nodes.Set_Date_State(un) == nodes.Date_State.Disk:
@@ -319,7 +336,7 @@ class Workspace(object):
def apply_changes(self, doc_uri, contentChanges, new_version):
doc = self.get_document(doc_uri)
- assert doc is not None, 'try to modify a non-loaded document'
+ assert doc is not None, "try to modify a non-loaded document"
self.obsolete_doc(doc)
prev_sfe = doc._fe
for change in contentChanges:
@@ -338,15 +355,18 @@ class Workspace(object):
pass
def apply_edit(self, edit):
- return self._server.request('workspace/applyEdit', {'edit': edit})
+ return self._server.request("workspace/applyEdit", {"edit": edit})
def publish_diagnostics(self, doc_uri, diagnostics):
- self._server.notify('textDocument/publishDiagnostics',
- params={'uri': doc_uri, 'diagnostics': diagnostics})
+ self._server.notify(
+ "textDocument/publishDiagnostics",
+ params={"uri": doc_uri, "diagnostics": diagnostics},
+ )
def show_message(self, message, msg_type=lsp.MessageType.Info):
- self._server.notify('window/showMessage',
- params={'type': msg_type, 'message': message})
+ self._server.notify(
+ "window/showMessage", params={"type": msg_type, "message": message}
+ )
def declaration_to_location(self, decl):
"Convert declaration :param decl: to an LSP Location"
@@ -359,10 +379,14 @@ class Workspace(object):
return None
fe = files_map.Location_To_File(decl_loc)
doc = self.sfe_to_document(fe)
- res = {'uri': doc.uri}
+ res = {"uri": doc.uri}
nid = nodes.Get_Identifier(decl)
- res['range'] = {'start': symbols.location_to_position(fe, decl_loc),
- 'end': symbols.location_to_position(fe, decl_loc + name_table.Get_Name_Length(nid))}
+ res["range"] = {
+ "start": symbols.location_to_position(fe, decl_loc),
+ "end": symbols.location_to_position(
+ fe, decl_loc + name_table.Get_Name_Length(nid)
+ ),
+ }
return res
def goto_definition(self, doc_uri, position):
@@ -383,10 +407,14 @@ class Workspace(object):
res = []
for fe in range(1, files_map.Get_Last_Source_File_Entry() + 1):
doc = self._fe_map.get(fe, None)
- res.append({'fe': fe,
- 'uri': doc.uri if doc is not None else None,
- 'name': pyutils.name_image(files_map.Get_File_Name(fe)),
- 'dir': pyutils.name_image(files_map.Get_Directory_Name(fe))})
+ res.append(
+ {
+ "fe": fe,
+ "uri": doc.uri if doc is not None else None,
+ "name": pyutils.name_image(files_map.Get_File_Name(fe)),
+ "dir": pyutils.name_image(files_map.Get_Directory_Name(fe)),
+ }
+ )
return res
def x_get_all_entities(self):
@@ -405,7 +433,7 @@ class Workspace(object):
files = nodes.Get_Chain(files)
ents = [pyutils.name_image(nodes.Get_Identifier(e)) for e in ents]
lib_name = pyutils.name_image(nodes.Get_Identifier(lib))
- res.extend([{'name': n, 'library': lib_name} for n in ents])
+ res.extend([{"name": n, "library": lib_name} for n in ents])
lib = nodes.Get_Chain(lib)
return res
@@ -413,24 +441,33 @@ class Workspace(object):
def create_interfaces(inters):
res = []
while inters != nodes.Null_Iir:
- res.append({'name': name_table.Get_Name_Ptr(nodes.Get_Identifier(inters)).decode('latin-1')})
+ res.append(
+ {
+ "name": name_table.Get_Name_Ptr(
+ nodes.Get_Identifier(inters)
+ ).decode("latin-1")
+ }
+ )
inters = nodes.Get_Chain(inters)
return res
+
# Find library
- lib_id = name_table.Get_Identifier(library.encode('utf-8'))
+ lib_id = name_table.Get_Identifier(library.encode("utf-8"))
lib = libraries.Get_Library_No_Create(lib_id)
if lib == name_table.Null_Identifier:
return None
# Find entity
- ent_id = name_table.Get_Identifier(name.encode('utf-8'))
+ ent_id = name_table.Get_Identifier(name.encode("utf-8"))
unit = libraries.Find_Primary_Unit(lib, ent_id)
if unit == nodes.Null_Iir:
return None
ent = nodes.Get_Library_Unit(unit)
- return {'library': library,
- 'entity': name,
- 'generics': create_interfaces(nodes.Get_Generic_Chain(ent)),
- 'ports': create_interfaces(nodes.Get_Port_Chain(ent))}
+ return {
+ "library": library,
+ "entity": name,
+ "generics": create_interfaces(nodes.Get_Generic_Chain(ent)),
+ "ports": create_interfaces(nodes.Get_Port_Chain(ent)),
+ }
def compute_anti_dependences(self):
"""Return a dictionnary of anti dependencies for design unit"""