summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/project-ctags86
-rw-r--r--config.org11
-rw-r--r--lisp/yggdrasil-ui.el54
3 files changed, 117 insertions, 34 deletions
diff --git a/bin/project-ctags b/bin/project-ctags
index 4fccd90..f0216d0 100755
--- a/bin/project-ctags
+++ b/bin/project-ctags
@@ -30,6 +30,7 @@ IGNORED_DIRECTORIES = {
"tests",
}
PYTHON_SUFFIXES = {".py", ".pyi"}
+RUST_SUFFIXES = {".rs"}
C_SOURCE_SUFFIXES = {".c", ".cc", ".cpp", ".cxx", ".m", ".mm"}
C_HEADER_SUFFIXES = {".h", ".hh", ".hpp", ".hxx"}
NIX_CTAGS_OPTIONS = [
@@ -79,8 +80,10 @@ def parse_arguments():
parser.add_argument("--ctags")
parser.add_argument("--python")
parser.add_argument("--python-command")
+ parser.add_argument("--cargo")
parser.add_argument("--source", action="append", default=[])
parser.add_argument("--no-python-deps", action="store_true")
+ parser.add_argument("--no-rust-deps", action="store_true")
parser.add_argument("--no-c-deps", action="store_true")
return parser.parse_args()
@@ -228,6 +231,81 @@ def python_dependency_files(args, root, files):
return sorted(dependency_files), shlex.join(command), unresolved
+def cargo_command(args, root):
+ value = args.cargo or os.environ.get("PROJECT_CTAGS_CARGO")
+ if value:
+ path = Path(os.path.expandvars(os.path.expanduser(value)))
+ if not path.is_absolute():
+ path = root / path
+ return str(path.absolute())
+ return shutil.which("cargo")
+
+
+def rust_host_target(root):
+ rustc = shutil.which("rustc")
+ if rustc is None:
+ return None
+ result = subprocess.run(
+ [rustc, "-vV"],
+ cwd=root,
+ text=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.DEVNULL,
+ check=False,
+ )
+ if result.returncode == 0:
+ for line in result.stdout.splitlines():
+ if line.startswith("host: "):
+ return line.removeprefix("host: ")
+ return None
+
+
+def rust_dependency_files(args, root):
+ manifest = root / "Cargo.toml"
+ if not manifest.is_file():
+ return [], None
+ cargo = cargo_command(args, root)
+ if cargo is None:
+ return [], None
+ command = [
+ cargo,
+ "metadata",
+ "--format-version=1",
+ "--locked",
+ "--offline",
+ "--manifest-path",
+ str(manifest),
+ ]
+ target = rust_host_target(root)
+ if target:
+ command.extend(["--filter-platform", target])
+ result = subprocess.run(
+ command,
+ cwd=root,
+ text=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ check=False,
+ )
+ if result.returncode != 0:
+ if result.stderr:
+ print(result.stderr.rstrip(), file=sys.stderr)
+ return [], None
+ try:
+ metadata = json.loads(result.stdout)
+ except json.JSONDecodeError:
+ print("Could not read Cargo metadata", file=sys.stderr)
+ return [], None
+ workspace_members = set(metadata.get("workspace_members", []))
+ files = set()
+ for package in metadata.get("packages", []):
+ if package.get("id") in workspace_members:
+ continue
+ package_root = Path(package["manifest_path"]).resolve().parent
+ files.update(walk_files(package_root, RUST_SUFFIXES))
+ return sorted(files), cargo
+
+
def compilation_database(root):
path = root / "compile_commands.json"
if not path.is_file():
@@ -378,11 +456,15 @@ def main():
unresolved = []
if not args.no_python_deps:
python_files, python, unresolved = python_dependency_files(args, root, local_files)
+ rust_files = []
+ cargo = None
+ if not args.no_rust_deps:
+ rust_files, cargo = rust_dependency_files(args, root)
c_headers = []
if not args.no_c_deps:
c_headers = c_dependency_files(root, local_files)
extra_files = extra_source_files(args, root)
- all_files = sorted(set(local_files + python_files + c_headers + extra_files))
+ all_files = sorted(set(local_files + python_files + rust_files + c_headers + extra_files))
if not all_files:
raise SystemExit("No source files found")
@@ -392,6 +474,8 @@ def main():
print(f"python: {python}; {len(python_files)} dependency files")
if unresolved:
print(f"python unresolved: {', '.join(unresolved)}")
+ if cargo:
+ print(f"rust: {cargo}; {len(rust_files)} dependency files")
if c_headers:
print(f"c: {len(c_headers)} dependency headers")
if extra_files:
diff --git a/config.org b/config.org
index 66ad919..7638999 100644
--- a/config.org
+++ b/config.org
@@ -2606,6 +2606,7 @@ Auto switch silos (different workspaces/folders) based on preconfigured director
(helm-move-to-line-cycle-in-source nil)
(helm-split-window-inside-p t)
(helm-autoresize-mode 1)
+ (helm-buffers-show-icons t)
(helm-boring-buffer-regexp-list
'("\\` "
"\\`\\*helm"
@@ -2797,6 +2798,16 @@ Built-in tree-sitter mode (Emacs 29+). The =c= grammar ships via =treesit-gramma
(c-ts-mode-indent-style 'k&r))
#+end_src
+** rust-ts-mode
+
+#+begin_src emacs-lisp
+(use-package rust-ts-mode
+ :ensure nil
+ :mode "\\.rs\\'"
+ :custom
+ (rust-ts-indent-offset 4))
+#+end_src
+
** python-ts-mode
Because I have to and not want to.
diff --git a/lisp/yggdrasil-ui.el b/lisp/yggdrasil-ui.el
index 1d4d1c0..17db379 100644
--- a/lisp/yggdrasil-ui.el
+++ b/lisp/yggdrasil-ui.el
@@ -34,16 +34,6 @@
:type 'string
:group 'yggdrasil-ui)
-(defcustom yggdrasil-ui-service-program "systemctl"
- "Program used to query the Yggdrasil service state."
- :type 'string
- :group 'yggdrasil-ui)
-
-(defcustom yggdrasil-ui-service-name "yggdrasil"
- "System service name for Yggdrasil."
- :type 'string
- :group 'yggdrasil-ui)
-
(defcustom yggdrasil-ui-known-hosts
'(("chiefsosa" . "201:6904:7fcb:6fa6:b869:48cc:a863:e9a6")
("md" . "202:5e97:a5ba:a207:ce38:ac4a:ca3:8f86")
@@ -153,36 +143,34 @@ Return (EXIT OUTPUT)."
"Run yggdrasilctl ARGS and decode JSON.
Return (ok VALUE) or (error MESSAGE)."
(pcase-let ((`(,code ,out) (apply #'yggdrasil-ui--run args)))
- (if (zerop code)
- (condition-case err
- (list 'ok (json-parse-string out
- :object-type 'alist
- :array-type 'list
- :null-object nil
- :false-object nil))
- (error (list 'error (error-message-string err))))
+ (cond
+ ((not (zerop code))
(list 'error (if (string-empty-p out)
(format "%s exited %s" yggdrasil-ui-control-program code)
- out)))))
-
-(defun yggdrasil-ui--service-state ()
- "Return the local service state as a string."
- (with-temp-buffer
- (let ((code (condition-case nil
- (call-process yggdrasil-ui-service-program nil t nil
- "is-active" yggdrasil-ui-service-name)
- (error 127)))
- (out (string-trim (buffer-string))))
- (cond ((zerop code) out)
- ((string-empty-p out) "unknown")
- (t out)))))
+ out)))
+ ((string-empty-p out)
+ (list 'error (format "%s returned no output"
+ yggdrasil-ui-control-program)))
+ ((not (member (substring out 0 1) '("{" "[")))
+ ;; Yggdrasil 0.5.14 can print a fatal connection error to stdout and
+ ;; still exit successfully. Preserve that useful error instead of
+ ;; reporting a misleading JSON parser failure.
+ (list 'error out))
+ (t
+ (condition-case err
+ (list 'ok (json-parse-string out
+ :object-type 'alist
+ :array-type 'list
+ :null-object nil
+ :false-object nil))
+ (error (list 'error (error-message-string err))))))))
(defun yggdrasil-ui--snapshot ()
"Collect current Yggdrasil status."
(let ((self (yggdrasil-ui--json "getSelf"))
(peers (yggdrasil-ui--json "getPeers")))
(list :updated (format-time-string "%Y-%m-%d %H:%M:%S")
- :service (yggdrasil-ui--service-state)
+ :service (if (eq (car self) 'ok) "active" "unavailable")
:self (and (eq (car self) 'ok) (cadr self))
:self-error (and (eq (car self) 'error) (cadr self))
:peers (and (eq (car peers) 'ok) (alist-get 'peers (cadr peers)))
@@ -237,7 +225,7 @@ Return (ok VALUE) or (error MESSAGE)."
'yggdrasil-ui-salient)
((or (null state)
(eq state 'down)
- (member state '("inactive" "Down")))
+ (member state '("inactive" "Down" "unavailable")))
'yggdrasil-ui-critical)
(t 'yggdrasil-ui-warning)))