Skip to content

Commit 2efc2dc

Browse files
committed
Adds command line option --config
The option allows for arbtrary name/location of the config file. In addition, it exposes the rest of the commad line interface to the configuration options file under the same names TODO: update README config arguments
1 parent 9e73460 commit 2efc2dc

File tree

4 files changed

+94
-71
lines changed

4 files changed

+94
-71
lines changed

README.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
[![image](https://img.shields.io/github/license/gnikit/fortran-language-server.svg)](https://github.com/gnikit/fortran-language-server/blob/master/LICENSE)
66
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
77

8-
`fortls`: A Fortran implementation of the [Language Server Protocol](https://github.com/Microsoft/language-server-protocol)
9-
(LSP) using Python (3.6+).
8+
`fortls` is an implementation of the [Language Server Protocol](https://github.com/Microsoft/language-server-protocol)
9+
(LSP) for Fortran using Python (3.6+).
1010

1111
Editor extensions that can integrate with `fortls` to provide autocomplete and
1212
other IDE-like functionality are available for
13-
[Visual Studio Code](https://github.com/krvajal/vscode-fortran-support)
13+
[Visual Studio Code](https://github.com/krvajal/vscode-fortran-support),
1414
[Atom](https://atom.io/packages/ide-fortran),
1515
[Visual Studio](https://github.com/michaelkonecny/vs-fortran-ls-client),
1616
[(Neo)vim](https://github.com/hansec/fortran-language-server/wiki/Using-forts-with-vim),
@@ -71,6 +71,7 @@ pip install fortls
7171
The following global settings can be used when launching the language
7272
server.
7373

74+
- `--config` Configuration options file (default: `.fortls`)
7475
- `--nthreads` Number of threads to use during workspace
7576
initialization (default: 4)
7677
- `--notify_init` Send notification message when workspace
@@ -139,8 +140,11 @@ fortls
139140

140141
## Configuration
141142

142-
Project specific settings can be specified by placing a JSON file named
143-
`.fortls` (example below) in the `root_dir` directory.
143+
Project specific settings can be specified by creating a **options** JSON file.
144+
You can specify the location and name of the file with the `--config` option.
145+
By default the options file is assumed to be `root_dir` with the name `.fortls`.
146+
147+
All command line options are also available through the **options** file as well.
144148

145149
- `lowercase_intrinsics` Use lowercase for intrinsics and keywords in
146150
autocomplete requests (default: false)
@@ -164,7 +168,7 @@ the project.
164168
### Excluding folders and file extensions
165169

166170
Directories and files can be excluded from the project by specifying
167-
their paths in the `excl_paths` variable in the`.fortls` file.
171+
their paths in the `excl_paths` variable in the options file.
168172
Paths can be absolute or relative to `root_dir`.
169173

170174
Excluded directories **will not** exclude all sub-directories.
@@ -178,11 +182,10 @@ Source files with a common suffix may also be excluded using the
178182

179183
By default all source directories under `root_dir` are recursively included.
180184
Source file directories can also be specified manually by specifying
181-
their paths in the `source_dirs` variable in `.fortls`.
185+
their paths in the `source_dirs` variable in the configuration options file.
182186
Paths can be absolute or relative to `root_dir`.
183-
the `.fortls` file.
184187

185-
When defining `source_dirs` in `.fortls` the default behaviour (i.e. including
188+
When defining `source_dirs` in the configuration options filethe default behaviour (i.e. including
186189
all files in all subdirectories under `root_dir`) is overriden. To include them
187190
back again one can do
188191

@@ -207,25 +210,25 @@ preprocessing (ie. tracking definitions). Fortran objects defined in
207210
these files will not be processed.
208211

209212
File suffixes for preprocessing can be controlled with the variable
210-
`pp_suffixes` in a workspace's `.fortls` file. When this variable is
213+
`pp_suffixes` in a workspace's configuration options file. When this variable is
211214
used _only_ those files with the specified suffixes will be
212215
preprocessed. If an empty array is specified then _no_ preprocessing
213216
will be performed on any files. By default, or if the variable is
214217
omitted or `null`, only files with upper case suffixes are preprocessed.
215218

216219
Preprocessor definitions can be set for each project, to improve support
217220
for Fortran files using conditional compilation, using the `pp_defs`
218-
variable in the `.fortls` file. Preprocessing is performed _only_ for
221+
variable in the configuration options file. Preprocessing is performed _only_ for
219222
files where the file extension is all caps (ie. ".F90", ".F", etc.).
220223
Currently, support for preprocessing is limited to variables declared in
221-
the project's `.fortls` file or in the source file of interest as
224+
the project's configuration options file or in the source file of interest as
222225
`#include` files and inheritance through `USE` statements are yet not
223226
supported. Variable substitution is also performed within files, but is
224227
currently limited to non-recursive cases. For example, `#define PP_VAR1 PP_VAR2` will cause `PP_VAR1` to be replaced with the text `PP_VAR2`
225228
throughout the file, not that value of `PP_VAR2`.
226229

227230
Include directories can be specified using the variable `include_dirs`
228-
in a workspace's `.fortls` file. These directories are _only_ used to
231+
in a workspace's configuration options file. These directories are _only_ used to
229232
search for preprocessor `#include`'d files. The directory containing the
230233
file where an `#include` statement is encountered is always searched.
231234
File search is performed starting with the containing directory followed

fortls/__init__.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,21 @@ def main():
5959

6060

6161
def parse_args():
62-
"""Parses the command line aguments to the Language Server
62+
"""Parses the command line arguments to the Language Server
6363
6464
Returns
6565
-------
6666
Namespace
6767
command line arguments
6868
"""
6969
parser = argparse.ArgumentParser()
70-
parser.description = "FORTRAN Language Server ({0})".format(__version__)
70+
parser.description = "fortls ({0})".format(__version__)
7171
parser.add_argument(
7272
"--version", action="store_true", help="Print server version number and exit"
7373
)
74+
parser.add_argument(
75+
"--config", type=str, default=".fortls", help="Configuration options file"
76+
)
7477
parser.add_argument(
7578
"--nthreads",
7679
type=int,
@@ -272,6 +275,7 @@ def set_settings(args):
272275
settings for the Language Server
273276
"""
274277
settings = {
278+
"config": args.config,
275279
"nthreads": args.nthreads,
276280
"notify_init": args.notify_init,
277281
"symbol_include_mem": (not args.symbol_skip_mem),
@@ -288,6 +292,7 @@ def set_settings(args):
288292
"max_line_length": args.max_line_length,
289293
"max_comment_line_length": args.max_comment_line_length,
290294
"disable_diagnostics": args.disable_diagnostics,
295+
291296
}
292297
if args.hover_language is not None:
293298
settings["hover_language"] = args.hover_language
@@ -702,7 +707,7 @@ def debug_server_parser(args):
702707
pp_defs = {}
703708
include_dirs = []
704709
if args.debug_rootpath:
705-
config_path = os.path.join(args.debug_rootpath, ".fortls")
710+
config_path = os.path.join(args.debug_rootpath, args.config)
706711
config_exists = os.path.isfile(config_path)
707712
if config_exists:
708713
try:
@@ -719,7 +724,7 @@ def debug_server_parser(args):
719724
if isinstance(pp_defs, list):
720725
pp_defs = {key: "" for key in pp_defs}
721726
except:
722-
print("Error while parsing '.fortls' settings file")
727+
print(f"Error while parsing '{args.config}' settings file")
723728
#
724729
print("\nTesting parser")
725730
print(' File = "{0}"'.format(args.debug_filepath))

fortls/langserver.py

Lines changed: 67 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def only_dirs(paths: list[str], err_msg: list = []) -> list[str]:
141141
continue
142142
else:
143143
msg: str = (
144-
f"Directory '{p}' specified in '.fortls' settings file does not exist"
144+
f"Directory '{p}' specified in Configuration settings file does not exist"
145145
)
146146
if err_msg:
147147
err_msg.append([2, msg])
@@ -177,6 +177,7 @@ def __init__(self, conn, debug_log=False, settings={}):
177177
self.intrinsic_mods,
178178
) = load_intrinsics()
179179
# Get launch settings
180+
self.config = settings.get("config", ".fortls")
180181
self.nthreads = settings.get("nthreads", 4)
181182
self.notify_init = settings.get("notify_init", False)
182183
self.symbol_include_mem = settings.get("symbol_include_mem", True)
@@ -1475,8 +1476,7 @@ def __load_config_file(self) -> None:
14751476
"""Loads the configuration file for the Language Server"""
14761477

14771478
# Check for config file
1478-
config_fname = ".fortls"
1479-
config_path = os.path.join(self.root_path, config_fname)
1479+
config_path = os.path.join(self.root_path, self.config)
14801480
if not os.path.isfile(config_path):
14811481
return None
14821482

@@ -1489,63 +1489,81 @@ def __load_config_file(self) -> None:
14891489
# config_dict = json.loads(jsondata)
14901490
config_dict = json.load(jsonfile)
14911491

1492-
# Exclude paths (directories & files)
1493-
# with glob resolution
1494-
for path in config_dict.get("excl_paths", []):
1495-
self.excl_paths.update(set(resolve_globs(path, self.root_path)))
1496-
1497-
# Source directory paths (directories)
1498-
# with glob resolution
1499-
source_dirs = config_dict.get("source_dirs", [])
1500-
for path in source_dirs:
1501-
self.source_dirs.update(
1502-
set(
1503-
only_dirs(
1504-
resolve_globs(path, self.root_path),
1505-
self.post_messages,
1506-
)
1507-
)
1508-
)
1509-
# Keep all directories present in source_dirs but not excl_paths
1510-
self.source_dirs = {
1511-
i for i in self.source_dirs if i not in self.excl_paths
1512-
}
1492+
# Include and Exclude directories
1493+
self.__load_config_file_dirs(config_dict)
15131494

1514-
self.excl_suffixes = config_dict.get("excl_suffixes", [])
1515-
self.lowercase_intrinsics = config_dict.get(
1516-
"lowercase_intrinsics", self.lowercase_intrinsics
1517-
)
1495+
# General options
1496+
self.__load_config_file_general(config_dict)
1497+
1498+
# Preprocessor options
1499+
self.__load_config_file_preproc(config_dict)
1500+
1501+
# Debug options
15181502
self.debug_log = config_dict.get("debug_log", self.debug_log)
1519-
self.disable_diagnostics = config_dict.get(
1520-
"disable_diagnostics", self.disable_diagnostics
1521-
)
1522-
self.pp_suffixes = config_dict.get("pp_suffixes", None)
1523-
self.pp_defs = config_dict.get("pp_defs", {})
1524-
for path in config_dict.get("include_dirs", []):
1525-
self.include_dirs.extend(
1526-
only_dirs(
1527-
resolve_globs(path, self.root_path), self.post_messages
1528-
)
1529-
)
1530-
self.max_line_length = config_dict.get(
1531-
"max_line_length", self.max_line_length
1532-
)
1533-
self.max_comment_line_length = config_dict.get(
1534-
"max_comment_line_length", self.max_comment_line_length
1535-
)
1536-
if isinstance(self.pp_defs, list):
1537-
self.pp_defs = {key: "" for key in self.pp_defs}
15381503

15391504
except FileNotFoundError:
1540-
msg = f"Error settings file '{config_fname}' not found"
1505+
msg = f"Error settings file '{self.config}' not found"
15411506
self.post_messages.append([1, msg])
15421507
log.error(msg)
15431508

15441509
except ValueError:
1545-
msg = f"Error while parsing '{config_fname}' settings file"
1510+
msg = f"Error while parsing '{self.config}' settings file"
15461511
self.post_messages.append([1, msg])
15471512
log.error(msg)
15481513

1514+
def __load_config_file_dirs(self, config_dict) -> None:
1515+
# Exclude paths (directories & files)
1516+
# with glob resolution
1517+
for path in config_dict.get("excl_paths", []):
1518+
self.excl_paths.update(set(resolve_globs(path, self.root_path)))
1519+
1520+
# Source directory paths (directories)
1521+
# with glob resolution
1522+
source_dirs = config_dict.get("source_dirs", [])
1523+
for path in source_dirs:
1524+
self.source_dirs.update(
1525+
set(
1526+
only_dirs(
1527+
resolve_globs(path, self.root_path),
1528+
self.post_messages,
1529+
)
1530+
)
1531+
)
1532+
# Keep all directories present in source_dirs but not excl_paths
1533+
self.source_dirs = {i for i in self.source_dirs if i not in self.excl_paths}
1534+
1535+
def __load_config_file_general(self, config_dict) -> None:
1536+
self.excl_suffixes = config_dict.get("excl_suffixes", [])
1537+
self.lowercase_intrinsics = config_dict.get(
1538+
"lowercase_intrinsics", self.lowercase_intrinsics
1539+
)
1540+
self.use_signature_help = config_dict.get(
1541+
"use_signature_help", self.use_signature_help
1542+
)
1543+
self.variable_hover = config_dict.get("variable_hover", self.variable_hover)
1544+
self.hover_signature = config_dict.get("hover_signature", self.hover_signature)
1545+
self.enable_code_actions = config_dict.get(
1546+
"enable_code_actions", self.enable_code_actions
1547+
)
1548+
self.disable_diagnostics = config_dict.get(
1549+
"disable_diagnostics", self.disable_diagnostics
1550+
)
1551+
self.max_line_length = config_dict.get("max_line_length", self.max_line_length)
1552+
self.max_comment_line_length = config_dict.get(
1553+
"max_comment_line_length", self.max_comment_line_length
1554+
)
1555+
1556+
def __load_config_file_preproc(self, config_dict) -> None:
1557+
self.pp_suffixes = config_dict.get("pp_suffixes", None)
1558+
self.pp_defs = config_dict.get("pp_defs", {})
1559+
if isinstance(self.pp_defs, list):
1560+
self.pp_defs = {key: "" for key in self.pp_defs}
1561+
1562+
for path in config_dict.get("include_dirs", []):
1563+
self.include_dirs.extend(
1564+
only_dirs(resolve_globs(path, self.root_path), self.post_messages)
1565+
)
1566+
15491567
def __add_source_dirs(self) -> None:
15501568
"""Will recursively add all subdirectories that contain Fortran
15511569
source files only if the option `source_dirs` has not been specified

setup.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
url="https://github.com/gnikit/fortran-language-server",
2323
author="Giannis Nikiteas",
2424
author_email="[email protected]",
25-
description="FORTRAN Language Server - dev version",
25+
description="fortls - Fortran Language Server",
2626
long_description=README,
2727
long_description_content_type="text/markdown",
2828
license="MIT",
@@ -47,10 +47,7 @@
4747
# simple. Or you can use find_packages().
4848
packages=find_packages(exclude=["contrib", "docs", "test"]),
4949
package_data={"fortls": ["*.json"]},
50-
# List run-time dependencies here. These will be installed by pip when
51-
# your project is installed. For an analysis of "install_requires" vs pip's
52-
# requirements files see:
53-
# https://packaging.python.org/en/latest/requirements.html
50+
# https://packaging.python.org/en/latest/discussions/install-requires-vs-requirements/
5451
install_requires=[
5552
'future; python_version < "3"',
5653
'argparse; python_version < "2.7" or python_version in "3.0, 3.1"',

0 commit comments

Comments
 (0)