clojure-mode with clojure-lsp as eglot backend

Add eglot-format to before-save-hook

Reformat all the nix files using nixpkgs-fmt

Redesign the WM mode modeline

Disable exwm mode. Posframe issue

Disable noether mode on WM until we fix the issue

Add the time unit to the modeline

Make eglot work with clojure-lsp
This commit is contained in:
Pouya Abbassi 2024-04-11 20:00:36 +03:30
parent 980566ea70
commit 209358c70d
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG Key ID: 591DF1A6C74C0CBC
17 changed files with 743 additions and 581 deletions

View File

@ -36,13 +36,14 @@
runtimeInputs = [ pkgs.xorg.xorgserver ]; runtimeInputs = [ pkgs.xorg.xorgserver ];
text = '' text = ''
${pkgs.xorg.xorgserver.out}/bin/Xephyr -br -ac -noreset -screen 800x600 :1 ${pkgs.xorg.xorgserver.out}/bin/Xephyr -br -ac -noreset -screen 800x600 :1
''; '';
}; };
noether = inputs.noether.outputs.packages.${system}.default; noether = inputs.noether.outputs.packages.${system}.default;
factory = params: pkgs.callPackage ./nix/factory.nix ({ inherit noether; } // params); factory = params: pkgs.callPackage ./nix/factory.nix ({ inherit noether; } // params);
default = (factory {}); default = (factory { });
in { in
{
packages = { packages = {
default = default.fg42; default = default.fg42;
} // (pkgs.lib.optionalAttrs (system == "x86_64-linux") { } // (pkgs.lib.optionalAttrs (system == "x86_64-linux") {
@ -58,7 +59,21 @@
nativeBuildInputs = [ default.fg42 pkgs.fish test-x default.run-test-wm ]; nativeBuildInputs = [ default.fg42 pkgs.fish test-x default.run-test-wm ];
buildInputs = [ default.fg42 ]; buildInputs = [ default.fg42 ];
}; };
};
apps.wm = {
type = "app";
program = "${default.run-test-wm}/bin/run-test-wm";
};
apps.x = {
type = "app";
program = "${test-x}/bin/test-x";
};
apps.default = {
type = "app";
program = "${default.fg42}/bin/fg42";
};
};
}; };
} }

View File

@ -52,7 +52,6 @@
gdscript-mode gdscript-mode
meson-mode meson-mode
lsp-scheme lsp-scheme
clojure-mode
cider cider
aggressive-indent aggressive-indent
graphviz-dot-mode graphviz-dot-mode
@ -90,6 +89,10 @@
org-ql org-ql
ctrlf ctrlf
badwolf-theme badwolf-theme
clojure-mode
clojure-ts-mode
cider
flycheck-clj-kondo
ace-window ace-window
avy avy
paredit paredit
@ -122,7 +125,8 @@
forge forge
svg-tag-mode svg-tag-mode
base16-theme base16-theme
consult) consult
nerd-icons-completion)
(provide 'fg42/deps) (provide 'fg42/deps)
;;; deps.el ends here ;;; deps.el ends here

View File

@ -26,11 +26,13 @@
;; Language support ;; Language support
(require 'fg42/autocomplete) (require 'fg42/autocomplete)
(require 'fg42/langs/langs) (require 'fg42/langs/langs)
(require 'fg42/eglot)
(require 'fg42/langs/cpp) (require 'fg42/langs/cpp)
(require 'fg42/langs/verilog) (require 'fg42/langs/verilog)
(require 'fg42/langs/python) (require 'fg42/langs/python)
(require 'fg42/langs/elisp) (require 'fg42/langs/elisp)
(require 'fg42/langs/nix) (require 'fg42/langs/nix)
(require 'fg42/langs/clojure)
(require 'fg42/git) (require 'fg42/git)
(require 'fg42/wm) (require 'fg42/wm)
@ -197,12 +199,6 @@ contextual information."
"Yasnippet's snippets." "Yasnippet's snippets."
:after yasnippet) :after yasnippet)
;; Language Servers and friends
(use! eglot
"Eglot is a minimalistic yet powerful LSP replacement
shipped with Emacs."
:commands eglot
:autoload eglot-ensure)
(use! flycheck (use! flycheck
"Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs." "Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs."
@ -270,7 +266,7 @@ shipped with Emacs."
;; git changes in the fringe ;; git changes in the fringe
(global-diff-hl-mode) (global-diff-hl-mode)
;; Modeline replacement ;; Modeline replacement
(noether-global-mode) (noether-global-mode)
;; Rectangular select ;; Rectangular select

39
lisp/fg42/eglot.el Normal file
View File

@ -0,0 +1,39 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://devheroes.codes/FG42/FG42
;; Version: 4.0.0
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;; Code:
(eval-when-compile
(require 'fpkg))
;; Language Servers and friends
(use! eglot
"Eglot is a minimalistic yet powerful LSP replacement
shipped with Emacs."
:hook
(prog-mode . eglot-ensure)
(prog-mode . (lambda ()
(add-hook 'before-save-hook 'eglot-format nil t))))
(provide 'fg42/eglot)
;;; eglot.el ends here

View File

@ -0,0 +1,57 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://devheroes.codes/FG42/FG42
;; Version: 4.0.0
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;; Code:
(eval-when-compile
(require 'fpkg))
(use! flycheck-clj-kondo
"flycheck linter for clojure using `clj-konda'"
:defer t)
;; (defun fg42/clojure-ts-mode-setup ()
;; "A hook handler to setup cpp related configurations."
;; ;; We set eglot's autoload command to `eglot-ensure'
;; (eglot-ensure))
(use! clojure-ts-mode
"Clojure mode"
;; :init
;; (add-to-list 'major-mode-remap-alist '(clojure-mode . clojure-ts-mode))
:mode (("\\.clj\\'" . clojure-ts-mode)
("\\.cljs\\'" . clojure-ts-mode)
("\\.cljc\\'" . clojure-ts-mode))
:config
(with-eval-after-load 'eglot
;; Force nil to use nixpkgs-fmt for formatting
(let ((clojure-lsp '(clojure-ts-mode . clojure-mode)))
(require 'flycheck-clj-kondo)
(add-to-list 'eglot-server-programs clojure-lsp)))
:hook
(clojure-ts-mode . company-mode)
(clojure-ts-mode . cider)
(clojure-ts-mode . eglot-ensure))
(provide 'fg42/langs/clojure)
;;; clojure.el ends here

View File

@ -24,13 +24,26 @@
(eval-when-compile (eval-when-compile
(require 'fpkg)) (require 'fpkg))
(use! nix-mode (use! nix-mode
"Nix language support for Emacs." "Nix language support for Emacs."
:mode "\\.nix\\'" :mode "\\.nix\\'"
:hook :hook
(nix-mode . eglot-ensure) (nix-mode . eglot-ensure)
(nix-mode . company-mode) (nix-mode . company-mode)
(nix-mode . flyspell-prog-mode)) (nix-mode . flyspell-prog-mode)
:init
:config
(with-eval-after-load 'eglot
;; Force nil to use nixpkgs-fmt for formatting
(let ((nil-lsp '(nix-mode . ("nil"
:initializationOptions
(:formatting (:command ["nixpkgs-fmt"]))))))
(add-to-list 'eglot-server-programs nil-lsp))))
(provide 'fg42/langs/nix) (provide 'fg42/langs/nix)
;;; nix.el ends here ;;; nix.el ends here

View File

@ -196,5 +196,14 @@ match all of the components in any order."
:bind (("M-g e" . consult-compile-error))) :bind (("M-g e" . consult-compile-error)))
(use! nerd-icons-completion
"Nerd icons in marginalia"
:after marginalia
:config
(nerd-icons-completion-mode)
(add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup))
(provide 'fg42/minibuffer) (provide 'fg42/minibuffer)
;;; minibuffer.el ends here ;;; minibuffer.el ends here

View File

@ -58,6 +58,7 @@ to Emacs modeline."
:commands noether-global-mode :commands noether-global-mode
:config :config
(require 'noether-views) (require 'noether-views)
(require 'fg42/modeline/views)
(let ((active-border (get-base16-color-or :base0A "#bd93f9")) (let ((active-border (get-base16-color-or :base0A "#bd93f9"))
(inactive-border (get-base16-color-or :base03 "#44475a"))) (inactive-border (get-base16-color-or :base03 "#44475a")))
@ -73,14 +74,11 @@ to Emacs modeline."
(if fg42/modeline-inactive-face fg42/modeline-inactive-face 'fg42/-disabled-modeline-dective-border) (if fg42/modeline-inactive-face fg42/modeline-inactive-face 'fg42/-disabled-modeline-dective-border)
(default-value 'face-remapping-alist) face-remaps)) (default-value 'face-remapping-alist) face-remaps))
;; Setup modelines
(when-not-wm (when-not-wm
(require 'fg42/modeline/views) (setq-default noether-views (list fg42/modeline)))
(when-not-wm
(setq-default noether-views (list fg42/modeline))))
(when-wm (when-wm
(setq-default noether-views (list fg42/minimal-exwm)))) (setq-default noether-views nil)))
(provide 'fg42/modeline) (provide 'fg42/modeline)
;;; modeline.el ends here ;;; modeline.el ends here

View File

@ -64,9 +64,12 @@
"Set the EXWM input mode for the current buffer." "Set the EXWM input mode for the current buffer."
(setq fg42/-exwm-input-mode (format "%s" exwm--input-mode))) (setq fg42/-exwm-input-mode (format "%s" exwm--input-mode)))
(defun fg42/-format-exwm-input-mode (_ v _ _) (defun fg42/-format-exwm-input-mode (_ v _ _)
"Just return the input mode name V." "Just return the input mode name V."
v) (if (=string v "line")
(propertize "L" 'font-lock-face `(:foreground ,(get-base16-color-or :base07 "eeeeec")))
(propertize "C" 'font-lock-face `(:foreground ,(get-base16-color-or :base0A "eeeeec")))))
(noether-defunit fg42/exwm-input-mode-unit (noether-defunit fg42/exwm-input-mode-unit

View File

@ -31,6 +31,10 @@
"Keep the modeline at bottom right by using the data from INFO." "Keep the modeline at bottom right by using the data from INFO."
(cons -1 -1)) (cons -1 -1))
(defun fg42/--bottom-right-padded (info)
"Keep the modeline at bottom right by using the data from INFO."
(cons -70 -1))
(defun fg42/adjust-modeline (view) (defun fg42/adjust-modeline (view)
"Adjust the VIEW after parent frame resize." "Adjust the VIEW after parent frame resize."
@ -58,7 +62,6 @@
(buffer-name-unit (buffer-name-unit
:label (format "%s " (nerd-icons-codicon "nf-cod-layers")) :label (format "%s " (nerd-icons-codicon "nf-cod-layers"))
:len 20) :len 20)
;; (mode-name-unit :label " " :len 4)
(projectile-project-unit (projectile-project-unit
:label (format "%s " (nerd-icons-octicon "nf-oct-project")) :label (format "%s " (nerd-icons-octicon "nf-oct-project"))
:len 20) :len 20)
@ -66,31 +69,33 @@
:label (format "%s " (nerd-icons-devicon "nf-dev-git_branch")) :label (format "%s " (nerd-icons-devicon "nf-dev-git_branch"))
:len 20) :len 20)
(fg42/mode-icon) (fg42/mode-icon)
(line-unit :label (format "%s " (nerd-icons-codicon "nf-cod-location"))))) (line-unit :label (format "%s " (nerd-icons-codicon "nf-cod-location")))
(time-unit :label (format " %s " (nerd-icons-mdicon "nf-md-clock_time_three")))))
(when-wm (noether-defview fg42/minimal-exwm
(noether-defview fg42/minimal-exwm "A super simple bar containing the line number and column number that
"A super simple bar containing the line number and column number that
Appears on the center of the current window." Appears on the center of the current window."
:managed? t :managed? t
:buffer "*exwm-status*" :buffer "*exwm-status*"
:binding (kbd "C-c 3") :binding (kbd "C-c 1")
:separator "|" :separator " | "
:frame
(list
;; Such a big numbers for X and Y will cause the frame to appear on the
;; bottom right corner and covering the minibuffer
:position '(-30 . -1)
:border-width 0
:timeout 5
:border-color "#bd93f9")
:units :timeout 10
(list :frame
(fg42/exwm-input-mode-unit :label "") (list
(buffer-name-unit :label "") :poshandler #'fg42/--bottom-right-padded
(time-unit :label "")))) :border-width 0
:border-color "#bd93f9")
:units
(list
(fg42/exwm-input-mode-unit :label (format "%s " (nerd-icons-faicon "nf-fa-linux")))
(buffer-name-unit
:label (format "%s " (nerd-icons-codicon "nf-cod-layers"))
:len 30)
(time-unit :label (format "%s " (nerd-icons-mdicon "nf-md-clock_time_three")))))
(provide 'fg42/modeline/views) (provide 'fg42/modeline/views)

View File

@ -13,14 +13,15 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
{ pkgs, lib, elispDepsFile }: { pkgs, lib, elispDepsFile }:
with builtins; with builtins;
let let
reader = import ./elisp_reader.nix { inherit lib; }; reader = import ./elisp_reader.nix { inherit lib; };
elispAst = reader.fromElisp (builtins.readFile elispDepsFile); elispAst = reader.fromElisp (builtins.readFile elispDepsFile);
dependsOnForm = filter (x: head x == "depends-on") elispAst; dependsOnForm = filter (x: head x == "depends-on") elispAst;
elispPkgs = if length dependsOnForm == 0 elispPkgs =
then throw "Can't find the form 'depends-on' on 'deps.el'" if length dependsOnForm == 0
else tail (head dependsOnForm); then throw "Can't find the form 'depends-on' on 'deps.el'"
in elispPkgs else tail (head dependsOnForm);
in
elispPkgs

View File

@ -1,33 +0,0 @@
# Fg42 - Emacs Editor for advance users
#
# Copyright (c) 2010-2024 Sameer Rahmani <lxsameer@gnu.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 2.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
{ pkgs, fg42, version }:
{
desktop = pkgs.writeText "FG42.desktop" ''
[Desktop Entry]
Encoding=UTF-8
Name=FG42
GenericName=FG42
Comment=Emacs Editor for advance users
MimeType=text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-java;application/x-shellscript;text/x-c;text/x-c++;text/x-ruby;text/x-python;text/x-clojure;text/css;text/html;text/x-javascript;
Type=Application
Terminal=false
Categories=Development;TextEditor;
StartupWMClass=FG42
Exec=${fg42} %F
Icon=fg42
Version=${version}
'';
}

View File

@ -25,18 +25,18 @@ let
# but only as far in as specified by maxLength. # but only as far in as specified by maxLength.
mkMatcher = regex: maxLength: mkMatcher = regex: maxLength:
string: string:
let let
substr = substring 0 maxLength string; substr = substring 0 maxLength string;
matched = match regex substr; matched = match regex substr;
in in
if matched != null then head matched else null; if matched != null then head matched else null;
removeStrings = stringsToRemove: string: removeStrings = stringsToRemove: string:
let let
len = length stringsToRemove; len = length stringsToRemove;
listOfNullStrings = genList (const "") len; listOfNullStrings = genList (const "") len;
in in
replaceStrings stringsToRemove listOfNullStrings string; replaceStrings stringsToRemove listOfNullStrings string;
# Split a string of elisp into individual tokens and add useful # Split a string of elisp into individual tokens and add useful
# metadata. # metadata.
@ -73,7 +73,8 @@ let
matchSymbol = matchSymbol =
let let
symbolChar = ''([^${notInSymbol}]|\\.)''; symbolChar = ''([^${notInSymbol}]|\\.)'';
in mkMatcher ''(${symbolChar}+)([${notInSymbol}]|$).*'' symbolMaxLength; in
mkMatcher ''(${symbolChar}+)([${notInSymbol}]|$).*'' symbolMaxLength;
maxTokenLength = foldl' max 0 [ maxTokenLength = foldl' max 0 [
commentMaxLength commentMaxLength
@ -125,173 +126,174 @@ let
dot = matchDot rest; dot = matchDot rest;
symbol = matchSymbol rest; symbol = matchSymbol rest;
in in
if state.skip > 0 then if state.skip > 0 then
state // { state // {
pos = state.pos + 1;
skip = state.skip - 1;
line = if char == "\n" then state.line + 1 else state.line;
}
else if char == "\n" then
let
mod = state.line / 1000;
newState = {
pos = state.pos + 1; pos = state.pos + 1;
skip = state.skip - 1; line = state.line + 1;
line = if char == "\n" then state.line + 1 else state.line; inherit mod;
} };
else if char == "\n" then in
let state // (
mod = state.line / 1000; # Force evaluation of old state every 1000 lines. Nix
newState = { # doesn't have a modulo builtin, so we have to save
pos = state.pos + 1; # the result of an integer division and compare
line = state.line + 1; # between runs.
inherit mod; if mod > state.mod then
}; seq state.acc newState
in
state // (
# Force evaluation of old state every 1000 lines. Nix
# doesn't have a modulo builtin, so we have to save
# the result of an integer division and compare
# between runs.
if mod > state.mod then
seq state.acc newState
else
newState
)
else if elem char [ " " "\t" "\r" ] then
state // {
pos = state.pos + 1;
inherit (state) line;
}
else if char == ";" then
if comment != null then
state // {
pos = state.pos + 1;
skip = (stringLength comment) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if char == "(" then
state // {
acc = state.acc ++ [{ type = "openParen"; value = "("; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == ")" then
state // {
acc = state.acc ++ [{ type = "closeParen"; value = ")"; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == "[" then
state // {
acc = state.acc ++ [{ type = "openBracket"; value = "["; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == "]" then
state // {
acc = state.acc ++ [{ type = "closeBracket"; value = "]"; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == "'" then
state // {
acc = state.acc ++ [{ type = "quote"; value = "'"; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == ''"'' then
if string != null then
state // {
acc = state.acc ++ [{ type = "string"; value = string; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength string) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if char == "#" then
let nextChar = substring 1 1 rest;
in
if nextChar == "'" then
state // {
acc = state.acc ++ [{ type = "function"; value = "#'"; inherit (state) line; }];
pos = state.pos + 1;
skip = 1;
}
else if nextChar == "&" then
if boolVector != null then
state // {
acc = state.acc ++ [{ type = "boolVector"; value = boolVector; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength boolVector) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if nextChar == "s" then
if substring 2 1 rest == "(" then
state // {
acc = state.acc ++ [{ type = "record"; value = "#s"; inherit (state) line; }];
pos = state.pos + 1;
skip = 1;
}
else throw "List must follow #s in record on line ${toString state.line}: ${rest}"
else if nextChar == "[" then
state // {
acc = state.acc ++ [{ type = "byteCode"; value = "#"; inherit (state) line; }];
pos = state.pos + 1;
}
else if nonBase10Integer != null then
state // {
acc = state.acc ++ [{ type = "nonBase10Integer"; value = nonBase10Integer; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength nonBase10Integer) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if elem char [ "+" "-" "." "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" ] then
if integer != null then
state // {
acc = state.acc ++ [{ type = "integer"; value = integer; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength integer) - 1;
}
else if float != null then
state // {
acc = state.acc ++ [{ type = "float"; value = float; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength float) - 1;
}
else if dot != null then
state // {
acc = state.acc ++ [{ type = "dot"; value = dot; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength dot) - 1;
}
else if symbol != null then
state // {
acc = state.acc ++ [{ type = "symbol"; value = symbol; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength symbol) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if char == "?" then
if character != null then
state // {
acc = state.acc ++ [{ type = "character"; value = character; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength character) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if char == "`" then
state // {
acc = state.acc ++ [{ type = "backquote"; value = "`"; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == "," then
if substring 1 1 rest == "@" then
state // {
acc = state.acc ++ [{ type = "slice"; value = ",@"; inherit (state) line; }];
skip = 1;
pos = state.pos + 1;
}
else else
newState
)
else if elem char [ " " "\t" "\r" ] then
state // {
pos = state.pos + 1;
inherit (state) line;
}
else if char == ";" then
if comment != null then
state // {
pos = state.pos + 1;
skip = (stringLength comment) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if char == "(" then
state // {
acc = state.acc ++ [{ type = "openParen"; value = "("; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == ")" then
state // {
acc = state.acc ++ [{ type = "closeParen"; value = ")"; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == "[" then
state // {
acc = state.acc ++ [{ type = "openBracket"; value = "["; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == "]" then
state // {
acc = state.acc ++ [{ type = "closeBracket"; value = "]"; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == "'" then
state // {
acc = state.acc ++ [{ type = "quote"; value = "'"; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == ''"'' then
if string != null then
state // {
acc = state.acc ++ [{ type = "string"; value = string; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength string) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if char == "#" then
let nextChar = substring 1 1 rest;
in
if nextChar == "'" then
state // {
acc = state.acc ++ [{ type = "function"; value = "#'"; inherit (state) line; }];
pos = state.pos + 1;
skip = 1;
}
else if nextChar == "&" then
if boolVector != null then
state // { state // {
acc = state.acc ++ [{ type = "expand"; value = ","; inherit (state) line; }]; acc = state.acc ++ [{ type = "boolVector"; value = boolVector; inherit (state) line; }];
pos = state.pos + 1; pos = state.pos + 1;
skip = (stringLength boolVector) - 1;
} }
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if nextChar == "s" then
if substring 2 1 rest == "(" then
state // {
acc = state.acc ++ [{ type = "record"; value = "#s"; inherit (state) line; }];
pos = state.pos + 1;
skip = 1;
}
else throw "List must follow #s in record on line ${toString state.line}: ${rest}"
else if nextChar == "[" then
state // {
acc = state.acc ++ [{ type = "byteCode"; value = "#"; inherit (state) line; }];
pos = state.pos + 1;
}
else if nonBase10Integer != null then
state // {
acc = state.acc ++ [{ type = "nonBase10Integer"; value = nonBase10Integer; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength nonBase10Integer) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if elem char [ "+" "-" "." "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" ] then
if integer != null then
state // {
acc = state.acc ++ [{ type = "integer"; value = integer; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength integer) - 1;
}
else if float != null then
state // {
acc = state.acc ++ [{ type = "float"; value = float; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength float) - 1;
}
else if dot != null then
state // {
acc = state.acc ++ [{ type = "dot"; value = dot; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength dot) - 1;
}
else if symbol != null then else if symbol != null then
state // { state // {
acc = state.acc ++ [{ type = "symbol"; value = symbol; inherit (state) line; }]; acc = state.acc ++ [{ type = "symbol"; value = symbol; inherit (state) line; }];
pos = state.pos + 1; pos = state.pos + 1;
skip = (stringLength symbol) - 1; skip = (stringLength symbol) - 1;
} }
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if char == "?" then
if character != null then
state // {
acc = state.acc ++ [{ type = "character"; value = character; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength character) - 1;
}
else throw "Unrecognized token on line ${toString state.line}: ${rest}"
else if char == "`" then
state // {
acc = state.acc ++ [{ type = "backquote"; value = "`"; inherit (state) line; }];
pos = state.pos + 1;
}
else if char == "," then
if substring 1 1 rest == "@" then
state // {
acc = state.acc ++ [{ type = "slice"; value = ",@"; inherit (state) line; }];
skip = 1;
pos = state.pos + 1;
}
else else
throw "Unrecognized token on line ${toString state.line}: ${rest}"; state // {
in (builtins.foldl' readToken { acc = []; pos = 0; skip = 0; line = startLineNumber; mod = 0; } (stringToCharacters elisp)).acc; acc = state.acc ++ [{ type = "expand"; value = ","; inherit (state) line; }];
pos = state.pos + 1;
}
else if symbol != null then
state // {
acc = state.acc ++ [{ type = "symbol"; value = symbol; inherit (state) line; }];
pos = state.pos + 1;
skip = (stringLength symbol) - 1;
}
else
throw "Unrecognized token on line ${toString state.line}: ${rest}";
in
(builtins.foldl' readToken { acc = [ ]; pos = 0; skip = 0; line = startLineNumber; mod = 0; } (stringToCharacters elisp)).acc;
tokenizeElisp = elisp: tokenizeElisp = elisp:
tokenizeElisp' { inherit elisp; }; tokenizeElisp' { inherit elisp; };
@ -302,41 +304,43 @@ let
# Convert literal value tokens in a flat list to their # Convert literal value tokens in a flat list to their
# corresponding nix representation. # corresponding nix representation.
parseValues = tokens: parseValues = tokens:
map (token: map
if token.type == "string" then (token:
token // { if token.type == "string" then
value = substring 1 (stringLength token.value - 2) token.value; token // {
} value = substring 1 (stringLength token.value - 2) token.value;
else if token.type == "integer" then }
token // { else if token.type == "integer" then
value = fromJSON (removeStrings ["+" "."] token.value); token // {
} value = fromJSON (removeStrings [ "+" "." ] token.value);
else if token.type == "symbol" && token.value == "t" then }
token // { else if token.type == "symbol" && token.value == "t" then
value = true; token // {
} value = true;
else if token.type == "float" then }
let else if token.type == "float" then
initial = head (match "([+-]?([[:digit:]]*[.])?[[:digit:]]+(e([+-]?[[:digit:]]+|[+](INF|NaN)))?)" token.value); let
isSpecial = (match "(.+(e[+](INF|NaN)))" initial) != null; initial = head (match "([+-]?([[:digit:]]*[.])?[[:digit:]]+(e([+-]?[[:digit:]]+|[+](INF|NaN)))?)" token.value);
withoutPlus = removeStrings ["+"] initial; isSpecial = (match "(.+(e[+](INF|NaN)))" initial) != null;
withPrefix = withoutPlus = removeStrings [ "+" ] initial;
if substring 0 1 withoutPlus == "." then withPrefix =
"0" + withoutPlus if substring 0 1 withoutPlus == "." then
else if substring 0 2 withoutPlus == "-." then "0" + withoutPlus
"-0" + removeStrings ["-"] withoutPlus else if substring 0 2 withoutPlus == "-." then
else "-0" + removeStrings [ "-" ] withoutPlus
withoutPlus; else
in withoutPlus;
in
if !isSpecial && withPrefix != null then if !isSpecial && withPrefix != null then
token // { token // {
value = fromJSON withPrefix; value = fromJSON withPrefix;
} }
else else
token token
else else
token token
) tokens; )
tokens;
# Convert pairs of opening and closing tokens to their # Convert pairs of opening and closing tokens to their
# respective collection types, i.e. lists and vectors. Also, # respective collection types, i.e. lists and vectors. Also,
@ -363,52 +367,52 @@ let
openColl = if token.type == "openParen" then "list" else if token.type == "openBracket" then "vector" else null; openColl = if token.type == "openParen" then "list" else if token.type == "openBracket" then "vector" else null;
closeColl = if token.type == "closeParen" then "list" else if token.type == "closeBracket" then "vector" else null; closeColl = if token.type == "closeParen" then "list" else if token.type == "closeBracket" then "vector" else null;
in in
if openColl != null then if openColl != null then
state // { state // {
acc = [ [] ] ++ seq (head state.acc) state.acc; acc = [ [ ] ] ++ seq (head state.acc) state.acc;
inColl = [ openColl ] ++ state.inColl; inColl = [ openColl ] ++ state.inColl;
depth = state.depth + 1; depth = state.depth + 1;
line = [ token.line ] ++ state.line; line = [ token.line ] ++ state.line;
} }
else if closeColl != null then else if closeColl != null then
if (head state.inColl) == closeColl then if (head state.inColl) == closeColl then
let
outerColl = elemAt state.acc 1;
currColl = {
type = closeColl;
value = head state.acc;
line = head state.line;
inherit (state) depth;
};
rest = tail (tail state.acc);
in
state // seq state.acc {
acc = [ (outerColl ++ [ currColl ]) ] ++ rest;
inColl = tail state.inColl;
depth = state.depth - 1;
line = tail state.line;
}
else
throw "Unmatched ${token.type} on line ${toString token.line}"
else if token.type == "symbol" && token.value == "nil" then
let let
currColl = head state.acc; outerColl = elemAt state.acc 1;
rest = tail state.acc; currColl = {
emptyList = { type = closeColl;
type = "list"; value = head state.acc;
depth = state.depth + 1; line = head state.line;
value = []; inherit (state) depth;
}; };
rest = tail (tail state.acc);
in in
state // seq currColl { acc = [ (currColl ++ [ emptyList ]) ] ++ rest; } state // seq state.acc {
acc = [ (outerColl ++ [ currColl ]) ] ++ rest;
inColl = tail state.inColl;
depth = state.depth - 1;
line = tail state.line;
}
else else
let throw "Unmatched ${token.type} on line ${toString token.line}"
currColl = head state.acc; else if token.type == "symbol" && token.value == "nil" then
rest = tail state.acc; let
in currColl = head state.acc;
state // seq currColl { acc = [ (currColl ++ [ token ]) ] ++ rest; }; rest = tail state.acc;
emptyList = {
type = "list";
depth = state.depth + 1;
value = [ ];
};
in
state // seq currColl { acc = [ (currColl ++ [ emptyList ]) ] ++ rest; }
else
let
currColl = head state.acc;
rest = tail state.acc;
in
state // seq currColl { acc = [ (currColl ++ [ token ]) ] ++ rest; };
in in
head (builtins.foldl' parseToken { acc = [ [] ]; inColl = [ null ]; depth = -1; line = []; } tokens).acc; head (builtins.foldl' parseToken { acc = [ [ ] ]; inColl = [ null ]; depth = -1; line = [ ]; } tokens).acc;
# Handle dotted pair notation, a syntax where the car and cdr # Handle dotted pair notation, a syntax where the car and cdr
# are represented explicitly. See # are represented explicitly. See
@ -434,33 +438,35 @@ let
throw ''"Dotted pair notation"-dot outside list on line ${toString token.line}'' throw ''"Dotted pair notation"-dot outside list on line ${toString token.line}''
else if isList token.value then else if isList token.value then
let let
collectionContents = foldl' parseToken { collectionContents = foldl' parseToken
acc = []; {
dotted = false; acc = [ ];
inList = token.type == "list"; dotted = false;
inherit (state) depthReduction; inList = token.type == "list";
} token.value; inherit (state) depthReduction;
}
token.value;
in in
state // { state // {
acc = state.acc ++ ( acc = state.acc ++ (
if state.dotted then if state.dotted then
collectionContents.acc collectionContents.acc
else else
[ [
(token // { (token // {
value = collectionContents.acc; value = collectionContents.acc;
depth = token.depth - state.depthReduction; depth = token.depth - state.depthReduction;
}) })
] ]
); );
dotted = false; dotted = false;
} }
else else
state // { state // {
acc = state.acc ++ [token]; acc = state.acc ++ [ token ];
}; };
in in
(foldl' parseToken { acc = []; dotted = false; inList = false; depthReduction = 0; } tokens).acc; (foldl' parseToken { acc = [ ]; dotted = false; inList = false; depthReduction = 0; } tokens).acc;
parseQuotes = tokens: parseQuotes = tokens:
let let
@ -469,35 +475,35 @@ let
token = token =
if isList token'.value then if isList token'.value then
token' // { token' // {
value = (foldl' parseToken { acc = []; quotes = []; } token'.value).acc; value = (foldl' parseToken { acc = [ ]; quotes = [ ]; } token'.value).acc;
} }
else else
token'; token';
in in
if elem token.type [ "quote" "expand" "slice" "backquote" "function" "record" "byteCode" ] then if elem token.type [ "quote" "expand" "slice" "backquote" "function" "record" "byteCode" ] then
state // { state // {
quotes = [ token ] ++ state.quotes; quotes = [ token ] ++ state.quotes;
} }
else if state.quotes != [] then else if state.quotes != [ ] then
let let
quote = value: token: quote = value: token:
token // { token // {
inherit value; inherit value;
}; };
quotedValue = foldl' quote token state.quotes; quotedValue = foldl' quote token state.quotes;
in in
state // { state // {
acc = state.acc ++ [ quotedValue ]; acc = state.acc ++ [ quotedValue ];
quotes = []; quotes = [ ];
} }
else else
state // { state // {
acc = state.acc ++ [ token ]; acc = state.acc ++ [ token ];
}; };
in in
(foldl' parseToken { acc = []; quotes = []; } tokens).acc; (foldl' parseToken { acc = [ ]; quotes = [ ]; } tokens).acc;
in in
parseQuotes (parseDots (parseCollections (parseValues tokens))); parseQuotes (parseDots (parseCollections (parseValues tokens)));
parseElisp = elisp: parseElisp = elisp:
parseElisp' (tokenizeElisp elisp); parseElisp' (tokenizeElisp elisp);
@ -508,23 +514,23 @@ let
if isList object.value then if isList object.value then
map readObject object.value map readObject object.value
else if object.type == "quote" then else if object.type == "quote" then
["quote" (readObject object.value)] [ "quote" (readObject object.value) ]
else if object.type == "backquote" then else if object.type == "backquote" then
["`" (readObject object.value)] [ "`" (readObject object.value) ]
else if object.type == "expand" then else if object.type == "expand" then
["," (readObject object.value)] [ "," (readObject object.value) ]
else if object.type == "slice" then else if object.type == "slice" then
[",@" (readObject object.value)] [ ",@" (readObject object.value) ]
else if object.type == "function" then else if object.type == "function" then
["#'" (readObject object.value)] [ "#'" (readObject object.value) ]
else if object.type == "byteCode" then else if object.type == "byteCode" then
["#"] ++ (readObject object.value) [ "#" ] ++ (readObject object.value)
else if object.type == "record" then else if object.type == "record" then
["#s"] ++ (readObject object.value) [ "#s" ] ++ (readObject object.value)
else else
object.value; object.value;
in in
map readObject ast; map readObject ast;
fromElisp = elisp: fromElisp = elisp:
fromElisp' (parseElisp elisp); fromElisp' (parseElisp elisp);
@ -570,135 +576,137 @@ let
force = expr: seq state.pos (seq state.line expr); force = expr: seq state.pos (seq state.line expr);
in in
if state.skip > 0 then if state.skip > 0 then
state // force { state // force {
pos = state.pos + 1; pos = state.pos + 1;
skip = state.skip - 1; skip = state.skip - 1;
line = if char == "\n" then state.line + 1 else state.line; line = if char == "\n" then state.line + 1 else state.line;
leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]); leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]);
} }
else if char == "#" && state.leadingWhitespace && !state.readBody && beginCodeBlock != null then else if char == "#" && state.leadingWhitespace && !state.readBody && beginCodeBlock != null then
state // {
pos = state.pos + 1;
skip = (stringLength beginCodeBlock) - 1;
leadingWhitespace = false;
readLanguage = true;
}
else if char == "#" && state.leadingWhitespace && !state.readBody && header != null then
state // {
pos = state.pos + 1;
skip = (stringLength header) - 1;
leadingWhitespace = false;
readFlags = true;
}
else if state.readLanguage then
if language != null then
state // { state // {
block = state.block // {
language = elemAt language 1;
};
pos = state.pos + 1; pos = state.pos + 1;
skip = (stringLength beginCodeBlock) - 1; skip = (foldl' (total: string: total + (stringLength string)) 0 language) - 1;
leadingWhitespace = false;
readLanguage = true;
}
else if char == "#" && state.leadingWhitespace && !state.readBody && header != null then
state // {
pos = state.pos + 1;
skip = (stringLength header) - 1;
leadingWhitespace = false; leadingWhitespace = false;
readLanguage = false;
readFlags = true; readFlags = true;
readBody = true;
} }
else if state.readLanguage then else throw "Language missing or invalid for code block on line ${toString state.line}!"
if language != null then else if state.readFlags then
state // { if flags != null then
block = state.block // { let
language = elemAt language 1; parseFlag = state: item:
}; let
pos = state.pos + 1; prefix = if isString item then substring 0 1 item else null;
skip = (foldl' (total: string: total + (stringLength string)) 0 language) - 1; in
leadingWhitespace = false; if elem prefix [ ":" "-" "+" ] then
readLanguage = false; state // {
readFlags = true; acc = state.acc // { ${item} = true; };
readBody = true; flag = item;
} }
else throw "Language missing or invalid for code block on line ${toString state.line}!" else if state.flag != null then
else if state.readFlags then state // {
if flags != null then acc = state.acc // { ${state.flag} = item; };
let flag = null;
parseFlag = state: item: }
let else
prefix = if isString item then substring 0 1 item else null; state;
in in
if elem prefix [ ":" "-" "+" ] then
state // {
acc = state.acc // { ${item} = true; };
flag = item;
}
else if state.flag != null then
state // {
acc = state.acc // { ${state.flag} = item; };
flag = null;
}
else
state;
in
state // {
block = state.block // {
flags =
(foldl'
parseFlag
{ acc = state.block.flags;
flag = null;
inherit (state) line;
}
(fromElisp flags)).acc;
startLineNumber = state.line + 1;
};
pos = state.pos + 1;
skip = (stringLength flags) - 1;
line = if char == "\n" then state.line + 1 else state.line;
leadingWhitespace = char == "\n";
readFlags = false;
}
else throw "Arguments malformed for code block on line ${toString state.line}!"
else if char == "#" && state.leadingWhitespace && endCodeBlock != null then
state // { state // {
acc = state.acc ++ [ state.block ]; block = state.block // {
block = { flags =
language = null; (foldl'
body = ""; parseFlag
flags = {}; {
acc = state.block.flags;
flag = null;
inherit (state) line;
}
(fromElisp flags)).acc;
startLineNumber = state.line + 1;
}; };
pos = state.pos + 1; pos = state.pos + 1;
skip = (stringLength endCodeBlock) - 1; skip = (stringLength flags) - 1;
leadingWhitespace = false; line = if char == "\n" then state.line + 1 else state.line;
readBody = false; leadingWhitespace = char == "\n";
readFlags = false;
} }
else if state.readBody then else throw "Arguments malformed for code block on line ${toString state.line}!"
let else if char == "#" && state.leadingWhitespace && endCodeBlock != null then
mod = state.pos / 100; state // {
newState = { acc = state.acc ++ [ state.block ];
block = state.block // { block = {
body = state.block.body + char; language = null;
}; body = "";
inherit mod; flags = { };
pos = state.pos + 1; };
line = if char == "\n" then state.line + 1 else state.line; pos = state.pos + 1;
leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]); skip = (stringLength endCodeBlock) - 1;
leadingWhitespace = false;
readBody = false;
}
else if state.readBody then
let
mod = state.pos / 100;
newState = {
block = state.block // {
body = state.block.body + char;
}; };
in inherit mod;
if mod > state.mod then
state // seq state.block.body (force newState)
else
state // newState
else
state // force {
pos = state.pos + 1; pos = state.pos + 1;
line = if char == "\n" then state.line + 1 else state.line; line = if char == "\n" then state.line + 1 else state.line;
leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]); leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]);
}; };
in in
(foldl' if mod > state.mod then
parseToken state // seq state.block.body (force newState)
{ acc = []; else
mod = 0; state // newState
pos = 0; else
skip = 0; state // force {
line = 1; pos = state.pos + 1;
block = { line = if char == "\n" then state.line + 1 else state.line;
language = null; leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]);
body = "";
flags = {};
}; };
leadingWhitespace = true; in
readLanguage = false; (foldl'
readFlags = false; parseToken
readBody = false; {
} acc = [ ];
(stringToCharacters text)).acc; mod = 0;
pos = 0;
skip = 0;
line = 1;
block = {
language = null;
body = "";
flags = { };
};
leadingWhitespace = true;
readLanguage = false;
readFlags = false;
readBody = false;
}
(stringToCharacters text)).acc;
# Run tokenizeElisp' on all Elisp code blocks (with `:tangle yes` # Run tokenizeElisp' on all Elisp code blocks (with `:tangle yes`
# set) from an Org mode babel text. If the block doesn't have a # set) from an Org mode babel text. If the block doesn't have a
@ -712,19 +720,19 @@ let
tangle = toLower (block.flags.":tangle" or defaultArgs.":tangle" or "no"); tangle = toLower (block.flags.":tangle" or defaultArgs.":tangle" or "no");
language = toLower block.language; language = toLower block.language;
in in
elem language [ "elisp" "emacs-lisp" ] elem language [ "elisp" "emacs-lisp" ]
&& elem tangle [ "yes" ''"yes"'' ]) && elem tangle [ "yes" ''"yes"'' ])
(parseOrgModeBabel text); (parseOrgModeBabel text);
in in
foldl' foldl'
(result: codeBlock: (result: codeBlock:
result ++ (tokenizeElisp' { result ++ (tokenizeElisp' {
elisp = codeBlock.body; elisp = codeBlock.body;
inherit (codeBlock) startLineNumber; inherit (codeBlock) startLineNumber;
}) })
) )
[] [ ]
codeBlocks; codeBlocks;
tokenizeOrgModeBabelElisp = tokenizeOrgModeBabelElisp =
tokenizeOrgModeBabelElisp' { tokenizeOrgModeBabelElisp' {

View File

@ -13,10 +13,15 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
{ lib, stdenv, emacs29, callPackage, writeShellApplication, noether { lib
, emacsParams ? {}, , stdenv
fg42Params ? {} , emacs29
} : , callPackage
, writeShellApplication
, noether
, emacsParams ? { }
, fg42Params ? { }
}:
let let
lemacs = emacs29.override ({ lemacs = emacs29.override ({
withTreeSitter = true; withTreeSitter = true;
@ -44,7 +49,8 @@ let
runtimeInputs = [ fg42 ]; runtimeInputs = [ fg42 ];
text = '' text = ''
DISPLAY=:1 ${fg42}/bin/fg42-wm DISPLAY=:1 ${fg42}/bin/fg42-wm
''; '';
}; };
in { inherit fg42 run-test-wm; } in
{ inherit fg42 run-test-wm; }

View File

@ -13,22 +13,51 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
{ lib, stdenv, elispPkgs, srcDir, emacsPackagesFor, ourPackages, direnv { lib
, makeFontsConf, nix , stdenv
, elispPkgs
, nil, # nix lsp server , srcDir
, emacsPackagesFor
, ourPackages
, direnv
, makeFontsConf
, nix
, nixpkgs-fmt
, nil
, # nix lsp server
# python deps # python deps
python311, python3Packages, python311
# This is a set of system tools required for FG42 , python3Packages
, # This is a set of system tools required for FG42
# to work. # to work.
pyright, emacs, ripgrep, git, texinfo, vazir-fonts, fira-code, nerdfonts pyright
, fira-mono, noto-fonts, gcc, ltex-ls, bash, tree-sitter, fd , emacs
, aspellWithDicts, , ripgrep
, git
supportWM ? true, xorg, slock, , texinfo
, vazir-fonts
supportPython ? true, supportVerilog ? true, svls, verilator, }: , fira-code
, nerdfonts
, fira-mono
, noto-fonts
, gcc
, ltex-ls
, bash
, tree-sitter
, fd
, aspellWithDicts
, supportWM ? true
, xorg
, slock
, supportPython ? true
, supportVerilog ? true
, supportClojure ? true
, svls
, verilator
, clojure-lsp
,
}:
with builtins; with builtins;
let let
version = "4.0.0"; version = "4.0.0";
@ -44,7 +73,15 @@ let
dicts = aspellWithDicts (dicts: with dicts; [ en en-computers en-science ]); dicts = aspellWithDicts (dicts: with dicts; [ en en-computers en-science ]);
runtimeBins = [ runtimeBins = [
ripgrep git tree-sitter direnv nix nil dicts fd ripgrep
git
tree-sitter
direnv
nix
nil
dicts
fd
nixpkgs-fmt
] ]
++ (lib.optional (!stdenv.buildPlatform.isRiscV) [ ++ (lib.optional (!stdenv.buildPlatform.isRiscV) [
# Not supported on Risc-V # Not supported on Risc-V
@ -64,12 +101,14 @@ let
# SystemC is required by verilator that at the # SystemC is required by verilator that at the
# moment is only available on Linux # moment is only available on Linux
verilator verilator
]) ++ (lib.optional (supportWM && stdenv.isLinux) [ ]) ++ (lib.optional (supportClojure) [ clojure-lsp ])
++ (lib.optional (supportWM && stdenv.isLinux) [
# Window manager supports works on Linux only # Window manager supports works on Linux only
xorg.xhost xorg.xhost
slock slock
]); ]);
paths = map (x: "${x}/bin/") (lib.lists.flatten runtimeBins); paths = map (x: "${x}/bin/") (lib.lists.flatten runtimeBins);
pathsStr = lib.strings.concatStrings (lib.strings.intersperse ":" paths); pathsStr = lib.strings.concatStrings (lib.strings.intersperse ":" paths);
@ -84,7 +123,8 @@ let
]; ];
}; };
in stdenv.mkDerivation (final: rec { in
stdenv.mkDerivation (final: rec {
inherit version; inherit version;
pname = "fg42"; pname = "fg42";
src = srcDir; src = srcDir;

View File

@ -18,7 +18,7 @@
lxsameer = { lxsameer = {
email = "lxsameer@lxsameer.com"; email = "lxsameer@lxsameer.com";
github = "lxsameer"; github = "lxsameer";
git = "lxsameer"; git = "lxsameer";
matrix = "@lxsameer:matrix.org"; matrix = "@lxsameer:matrix.org";
name = "Sameer Rahmani"; name = "Sameer Rahmani";
keys = [{ keys = [{

View File

@ -22,76 +22,77 @@ let
(x: builtins.typeOf x == "string") (x: builtins.typeOf x == "string")
(builtins.split _sep _s); (builtins.split _sep _s);
in { in
elispStr { elispStr
, alwaysEnsure ? false , alwaysEnsure ? false
}: }:
let let
inherit (import ./elisp_reader.nix { inherit lib; }) fromElisp; inherit (import ./elisp_reader.nix { inherit lib; }) fromElisp;
readFunction = fromElisp; readFunction = fromElisp;
find = item: list: find = item: list:
if list == [] then [] else if list == [ ] then [ ] else
if builtins.head list == item then if builtins.head list == item then
list list
else else
find item (builtins.tail list); find item (builtins.tail list);
getKeywordValue = keyword: list: getKeywordValue = keyword: list:
let
keywordList = find keyword list;
in
if keywordList != [ ] then
let let
keywordList = find keyword list; keywordValue = builtins.tail keywordList;
in in
if keywordList != [] then if keywordValue != [ ] then
let builtins.head keywordValue
keywordValue = builtins.tail keywordList;
in
if keywordValue != [] then
builtins.head keywordValue
else
true
else
null;
isDisabled = item:
let
disabledValue = getKeywordValue ":disabled" item;
in
if disabledValue == [] then
false
else if builtins.isBool disabledValue then
disabledValue
else if builtins.isString disabledValue then
true
else
false;
getName = item:
let
ensureValue = getKeywordValue ":ensure" item;
usePackageName = builtins.head (builtins.tail item);
in
if builtins.isString ensureValue then
if lib.hasPrefix ":" ensureValue then
usePackageName
else
ensureValue
else if ensureValue == true || (ensureValue == null && alwaysEnsure) then
usePackageName
else
[];
recurse = item:
if builtins.isList item && item != [] then
let
packageManager = builtins.head item;
in
if builtins.elem packageManager [ "depends-on" ] then
if !(isDisabled item) then
[ packageManager (getName item) ] ++ map recurse item
else
[]
else
map recurse item
else else
[]; true
in lib.flatten (map recurse (readFunction elispStr)) else
null;
isDisabled = item:
let
disabledValue = getKeywordValue ":disabled" item;
in
if disabledValue == [ ] then
false
else if builtins.isBool disabledValue then
disabledValue
else if builtins.isString disabledValue then
true
else
false;
getName = item:
let
ensureValue = getKeywordValue ":ensure" item;
usePackageName = builtins.head (builtins.tail item);
in
if builtins.isString ensureValue then
if lib.hasPrefix ":" ensureValue then
usePackageName
else
ensureValue
else if ensureValue == true || (ensureValue == null && alwaysEnsure) then
usePackageName
else
[ ];
recurse = item:
if builtins.isList item && item != [ ] then
let
packageManager = builtins.head item;
in
if builtins.elem packageManager [ "depends-on" ] then
if !(isDisabled item) then
[ packageManager (getName item) ] ++ map recurse item
else
[ ]
else
map recurse item
else
[ ];
in
lib.flatten (map recurse (readFunction elispStr))