diff --git a/flake.nix b/flake.nix index 20fee02..35ae0d1 100644 --- a/flake.nix +++ b/flake.nix @@ -36,13 +36,14 @@ runtimeInputs = [ pkgs.xorg.xorgserver ]; 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; factory = params: pkgs.callPackage ./nix/factory.nix ({ inherit noether; } // params); - default = (factory {}); - in { + default = (factory { }); + in + { packages = { default = default.fg42; } // (pkgs.lib.optionalAttrs (system == "x86_64-linux") { @@ -58,7 +59,21 @@ nativeBuildInputs = [ default.fg42 pkgs.fish test-x default.run-test-wm ]; 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"; + }; + + }; }; } diff --git a/lisp/fg42/deps.el b/lisp/fg42/deps.el index ac74824..bf45917 100644 --- a/lisp/fg42/deps.el +++ b/lisp/fg42/deps.el @@ -124,7 +124,8 @@ forge svg-tag-mode base16-theme - consult) + consult + nerd-icons-completion) (provide 'fg42/deps) ;;; deps.el ends here diff --git a/lisp/fg42/editor.el b/lisp/fg42/editor.el index d425ed2..6d7eda1 100644 --- a/lisp/fg42/editor.el +++ b/lisp/fg42/editor.el @@ -26,6 +26,7 @@ ;; Language support (require 'fg42/autocomplete) (require 'fg42/langs/langs) + (require 'fg42/eglot) (require 'fg42/langs/cpp) (require 'fg42/langs/verilog) (require 'fg42/langs/python) @@ -198,12 +199,6 @@ contextual information." "Yasnippet's snippets." :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 "Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs." @@ -271,7 +266,7 @@ shipped with Emacs." ;; git changes in the fringe (global-diff-hl-mode) - ;; Modeline replacement + ;; Modeline replacement (noether-global-mode) ;; Rectangular select diff --git a/lisp/fg42/eglot.el b/lisp/fg42/eglot.el new file mode 100644 index 0000000..b91977f --- /dev/null +++ b/lisp/fg42/eglot.el @@ -0,0 +1,39 @@ +;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*- +;; +;; Copyright (c) 2010-2024 Sameer Rahmani & Contributors +;; +;; Author: Sameer Rahmani +;; 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 . +;; +;;; 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 diff --git a/lisp/fg42/langs/nix.el b/lisp/fg42/langs/nix.el index 4fcbddd..b9ed6b8 100644 --- a/lisp/fg42/langs/nix.el +++ b/lisp/fg42/langs/nix.el @@ -24,13 +24,26 @@ (eval-when-compile (require 'fpkg)) + + (use! nix-mode "Nix language support for Emacs." :mode "\\.nix\\'" + :hook (nix-mode . eglot-ensure) (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) ;;; nix.el ends here diff --git a/lisp/fg42/minibuffer.el b/lisp/fg42/minibuffer.el index 2bdef3e..16f87c7 100644 --- a/lisp/fg42/minibuffer.el +++ b/lisp/fg42/minibuffer.el @@ -196,5 +196,14 @@ match all of the components in any order." :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) ;;; minibuffer.el ends here diff --git a/lisp/fg42/modeline.el b/lisp/fg42/modeline.el index 14221be..08ca2be 100644 --- a/lisp/fg42/modeline.el +++ b/lisp/fg42/modeline.el @@ -58,6 +58,7 @@ to Emacs modeline." :commands noether-global-mode :config (require 'noether-views) + (require 'fg42/modeline/views) (let ((active-border (get-base16-color-or :base0A "#bd93f9")) (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) (default-value 'face-remapping-alist) face-remaps)) + ;; Setup modelines (when-not-wm - (require 'fg42/modeline/views) - - (when-not-wm - (setq-default noether-views (list fg42/modeline)))) - + (setq-default noether-views (list fg42/modeline))) (when-wm - (setq-default noether-views (list fg42/minimal-exwm)))) + (setq-default noether-views nil))) (provide 'fg42/modeline) ;;; modeline.el ends here diff --git a/lisp/fg42/modeline/units.el b/lisp/fg42/modeline/units.el index 3b4ea13..7900167 100644 --- a/lisp/fg42/modeline/units.el +++ b/lisp/fg42/modeline/units.el @@ -64,9 +64,12 @@ "Set the EXWM input mode for the current buffer." (setq fg42/-exwm-input-mode (format "%s" exwm--input-mode))) + (defun fg42/-format-exwm-input-mode (_ 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 diff --git a/lisp/fg42/modeline/views.el b/lisp/fg42/modeline/views.el index 54c7466..7662162 100644 --- a/lisp/fg42/modeline/views.el +++ b/lisp/fg42/modeline/views.el @@ -31,6 +31,10 @@ "Keep the modeline at bottom right by using the data from INFO." (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) "Adjust the VIEW after parent frame resize." @@ -58,7 +62,6 @@ (buffer-name-unit :label (format "%s " (nerd-icons-codicon "nf-cod-layers")) :len 20) - ;; (mode-name-unit :label " " :len 4) (projectile-project-unit :label (format "%s " (nerd-icons-octicon "nf-oct-project")) :len 20) @@ -66,31 +69,33 @@ :label (format "%s " (nerd-icons-devicon "nf-dev-git_branch")) :len 20) (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 - "A super simple bar containing the line number and column number that +(noether-defview fg42/minimal-exwm + "A super simple bar containing the line number and column number that Appears on the center of the current window." - :managed? t - :buffer "*exwm-status*" - :binding (kbd "C-c 3") - :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") + :managed? t + :buffer "*exwm-status*" + :binding (kbd "C-c 1") + :separator " | " - :units - (list - (fg42/exwm-input-mode-unit :label "") - (buffer-name-unit :label "") - (time-unit :label "")))) + :timeout 10 + :frame + (list + :poshandler #'fg42/--bottom-right-padded + :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) diff --git a/nix/deps.nix b/nix/deps.nix index dcbdf3a..6d65e0e 100644 --- a/nix/deps.nix +++ b/nix/deps.nix @@ -13,14 +13,15 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - { pkgs, lib, elispDepsFile }: with builtins; let reader = import ./elisp_reader.nix { inherit lib; }; elispAst = reader.fromElisp (builtins.readFile elispDepsFile); dependsOnForm = filter (x: head x == "depends-on") elispAst; - elispPkgs = if length dependsOnForm == 0 - then throw "Can't find the form 'depends-on' on 'deps.el'" - else tail (head dependsOnForm); -in elispPkgs + elispPkgs = + if length dependsOnForm == 0 + then throw "Can't find the form 'depends-on' on 'deps.el'" + else tail (head dependsOnForm); +in +elispPkgs diff --git a/nix/desktop.nix b/nix/desktop.nix deleted file mode 100644 index 1fca586..0000000 --- a/nix/desktop.nix +++ /dev/null @@ -1,33 +0,0 @@ -# Fg42 - Emacs Editor for advance users -# -# Copyright (c) 2010-2024 Sameer Rahmani -# -# 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 . -{ 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} - ''; -} diff --git a/nix/elisp_reader.nix b/nix/elisp_reader.nix index f41cf8e..a1958c3 100644 --- a/nix/elisp_reader.nix +++ b/nix/elisp_reader.nix @@ -25,18 +25,18 @@ let # but only as far in as specified by maxLength. mkMatcher = regex: maxLength: string: - let - substr = substring 0 maxLength string; - matched = match regex substr; - in - if matched != null then head matched else null; + let + substr = substring 0 maxLength string; + matched = match regex substr; + in + if matched != null then head matched else null; removeStrings = stringsToRemove: string: let len = length stringsToRemove; listOfNullStrings = genList (const "") len; in - replaceStrings stringsToRemove listOfNullStrings string; + replaceStrings stringsToRemove listOfNullStrings string; # Split a string of elisp into individual tokens and add useful # metadata. @@ -73,7 +73,8 @@ let matchSymbol = let symbolChar = ''([^${notInSymbol}]|\\.)''; - in mkMatcher ''(${symbolChar}+)([${notInSymbol}]|$).*'' symbolMaxLength; + in + mkMatcher ''(${symbolChar}+)([${notInSymbol}]|$).*'' symbolMaxLength; maxTokenLength = foldl' max 0 [ commentMaxLength @@ -125,173 +126,174 @@ let dot = matchDot rest; symbol = matchSymbol rest; in - if state.skip > 0 then - state // { + if state.skip > 0 then + 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; - 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; - line = state.line + 1; - inherit mod; - }; - 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; - } + line = state.line + 1; + inherit mod; + }; + 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 = "expand"; value = ","; inherit (state) line; }]; + 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 - 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; + state // { + 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' { inherit elisp; }; @@ -302,41 +304,43 @@ let # Convert literal value tokens in a flat list to their # corresponding nix representation. parseValues = tokens: - map (token: - if token.type == "string" then - token // { - value = substring 1 (stringLength token.value - 2) token.value; - } - else if token.type == "integer" then - token // { - value = fromJSON (removeStrings ["+" "."] token.value); - } - else if token.type == "symbol" && token.value == "t" then - token // { - value = true; - } - else if token.type == "float" then - let - initial = head (match "([+-]?([[:digit:]]*[.])?[[:digit:]]+(e([+-]?[[:digit:]]+|[+](INF|NaN)))?)" token.value); - isSpecial = (match "(.+(e[+](INF|NaN)))" initial) != null; - withoutPlus = removeStrings ["+"] initial; - withPrefix = - if substring 0 1 withoutPlus == "." then - "0" + withoutPlus - else if substring 0 2 withoutPlus == "-." then - "-0" + removeStrings ["-"] withoutPlus - else - withoutPlus; - in + map + (token: + if token.type == "string" then + token // { + value = substring 1 (stringLength token.value - 2) token.value; + } + else if token.type == "integer" then + token // { + value = fromJSON (removeStrings [ "+" "." ] token.value); + } + else if token.type == "symbol" && token.value == "t" then + token // { + value = true; + } + else if token.type == "float" then + let + initial = head (match "([+-]?([[:digit:]]*[.])?[[:digit:]]+(e([+-]?[[:digit:]]+|[+](INF|NaN)))?)" token.value); + isSpecial = (match "(.+(e[+](INF|NaN)))" initial) != null; + withoutPlus = removeStrings [ "+" ] initial; + withPrefix = + if substring 0 1 withoutPlus == "." then + "0" + withoutPlus + else if substring 0 2 withoutPlus == "-." then + "-0" + removeStrings [ "-" ] withoutPlus + else + withoutPlus; + in if !isSpecial && withPrefix != null then token // { value = fromJSON withPrefix; } else token - else - token - ) tokens; + else + token + ) + tokens; # Convert pairs of opening and closing tokens to their # 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; closeColl = if token.type == "closeParen" then "list" else if token.type == "closeBracket" then "vector" else null; in - if openColl != null then - state // { - acc = [ [] ] ++ seq (head state.acc) state.acc; - inColl = [ openColl ] ++ state.inColl; - depth = state.depth + 1; - line = [ token.line ] ++ state.line; - } - else if closeColl != null 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 + if openColl != null then + state // { + acc = [ [ ] ] ++ seq (head state.acc) state.acc; + inColl = [ openColl ] ++ state.inColl; + depth = state.depth + 1; + line = [ token.line ] ++ state.line; + } + else if closeColl != null then + if (head state.inColl) == closeColl then let - currColl = head state.acc; - rest = tail state.acc; - emptyList = { - type = "list"; - depth = state.depth + 1; - value = []; + 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 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 - let - currColl = head state.acc; - rest = tail state.acc; - in - state // seq currColl { acc = [ (currColl ++ [ token ]) ] ++ rest; }; + throw "Unmatched ${token.type} on line ${toString token.line}" + else if token.type == "symbol" && token.value == "nil" then + let + currColl = head state.acc; + 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 - 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 # are represented explicitly. See @@ -434,33 +438,35 @@ let throw ''"Dotted pair notation"-dot outside list on line ${toString token.line}'' else if isList token.value then let - collectionContents = foldl' parseToken { - acc = []; - dotted = false; - inList = token.type == "list"; - inherit (state) depthReduction; - } token.value; + collectionContents = foldl' parseToken + { + acc = [ ]; + dotted = false; + inList = token.type == "list"; + inherit (state) depthReduction; + } + token.value; in - state // { - acc = state.acc ++ ( - if state.dotted then - collectionContents.acc - else - [ - (token // { - value = collectionContents.acc; - depth = token.depth - state.depthReduction; - }) - ] - ); - dotted = false; - } + state // { + acc = state.acc ++ ( + if state.dotted then + collectionContents.acc + else + [ + (token // { + value = collectionContents.acc; + depth = token.depth - state.depthReduction; + }) + ] + ); + dotted = false; + } else state // { - acc = state.acc ++ [token]; + acc = state.acc ++ [ token ]; }; 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: let @@ -469,35 +475,35 @@ let token = if isList token'.value then token' // { - value = (foldl' parseToken { acc = []; quotes = []; } token'.value).acc; + value = (foldl' parseToken { acc = [ ]; quotes = [ ]; } token'.value).acc; } else token'; in - if elem token.type [ "quote" "expand" "slice" "backquote" "function" "record" "byteCode" ] then - state // { - quotes = [ token ] ++ state.quotes; - } - else if state.quotes != [] then - let - quote = value: token: - token // { - inherit value; - }; - quotedValue = foldl' quote token state.quotes; - in - state // { - acc = state.acc ++ [ quotedValue ]; - quotes = []; - } - else - state // { - acc = state.acc ++ [ token ]; - }; + if elem token.type [ "quote" "expand" "slice" "backquote" "function" "record" "byteCode" ] then + state // { + quotes = [ token ] ++ state.quotes; + } + else if state.quotes != [ ] then + let + quote = value: token: + token // { + inherit value; + }; + quotedValue = foldl' quote token state.quotes; + in + state // { + acc = state.acc ++ [ quotedValue ]; + quotes = [ ]; + } + else + state // { + acc = state.acc ++ [ token ]; + }; in - (foldl' parseToken { acc = []; quotes = []; } tokens).acc; + (foldl' parseToken { acc = [ ]; quotes = [ ]; } tokens).acc; in - parseQuotes (parseDots (parseCollections (parseValues tokens))); + parseQuotes (parseDots (parseCollections (parseValues tokens))); parseElisp = elisp: parseElisp' (tokenizeElisp elisp); @@ -508,23 +514,23 @@ let if isList object.value then map readObject object.value else if object.type == "quote" then - ["quote" (readObject object.value)] + [ "quote" (readObject object.value) ] else if object.type == "backquote" then - ["`" (readObject object.value)] + [ "`" (readObject object.value) ] else if object.type == "expand" then - ["," (readObject object.value)] + [ "," (readObject object.value) ] else if object.type == "slice" then - [",@" (readObject object.value)] + [ ",@" (readObject object.value) ] else if object.type == "function" then - ["#'" (readObject object.value)] + [ "#'" (readObject object.value) ] else if object.type == "byteCode" then - ["#"] ++ (readObject object.value) + [ "#" ] ++ (readObject object.value) else if object.type == "record" then - ["#s"] ++ (readObject object.value) + [ "#s" ] ++ (readObject object.value) else object.value; in - map readObject ast; + map readObject ast; fromElisp = elisp: fromElisp' (parseElisp elisp); @@ -570,135 +576,137 @@ let force = expr: seq state.pos (seq state.line expr); in - if state.skip > 0 then - state // force { - pos = state.pos + 1; - skip = state.skip - 1; - line = if char == "\n" then state.line + 1 else state.line; - leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]); - } - else if char == "#" && state.leadingWhitespace && !state.readBody && beginCodeBlock != null then + if state.skip > 0 then + state // force { + pos = state.pos + 1; + skip = state.skip - 1; + line = if char == "\n" then state.line + 1 else state.line; + leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]); + } + 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 // { + block = state.block // { + language = elemAt language 1; + }; 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; + skip = (foldl' (total: string: total + (stringLength string)) 0 language) - 1; leadingWhitespace = false; + readLanguage = false; readFlags = true; + readBody = true; } - else if state.readLanguage then - if language != null then - state // { - block = state.block // { - language = elemAt language 1; - }; - pos = state.pos + 1; - skip = (foldl' (total: string: total + (stringLength string)) 0 language) - 1; - leadingWhitespace = false; - readLanguage = false; - readFlags = true; - readBody = true; - } - else throw "Language missing or invalid for code block on line ${toString state.line}!" - else if state.readFlags then - if flags != null then - let - parseFlag = state: item: - let - prefix = if isString item then substring 0 1 item else null; - 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 + else throw "Language missing or invalid for code block on line ${toString state.line}!" + else if state.readFlags then + if flags != null then + let + parseFlag = state: item: + let + prefix = if isString item then substring 0 1 item else null; + 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 // { - acc = state.acc ++ [ state.block ]; - block = { - language = null; - body = ""; - flags = {}; + 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 endCodeBlock) - 1; - leadingWhitespace = false; - readBody = false; + skip = (stringLength flags) - 1; + line = if char == "\n" then state.line + 1 else state.line; + leadingWhitespace = char == "\n"; + readFlags = false; } - else if state.readBody then - let - mod = state.pos / 100; - newState = { - block = state.block // { - body = state.block.body + char; - }; - inherit mod; - pos = state.pos + 1; - line = if char == "\n" then state.line + 1 else state.line; - leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]); + else throw "Arguments malformed for code block on line ${toString state.line}!" + else if char == "#" && state.leadingWhitespace && endCodeBlock != null then + state // { + acc = state.acc ++ [ state.block ]; + block = { + language = null; + body = ""; + flags = { }; + }; + pos = state.pos + 1; + 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 - if mod > state.mod then - state // seq state.block.body (force newState) - else - state // newState - else - state // force { + inherit mod; pos = state.pos + 1; line = if char == "\n" then state.line + 1 else state.line; leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]); }; - in - (foldl' - parseToken - { acc = []; - mod = 0; - pos = 0; - skip = 0; - line = 1; - block = { - language = null; - body = ""; - flags = {}; + in + if mod > state.mod then + state // seq state.block.body (force newState) + else + state // newState + else + state // force { + pos = state.pos + 1; + line = if char == "\n" then state.line + 1 else state.line; + leadingWhitespace = char == "\n" || (state.leadingWhitespace && elem char [ " " "\t" "\r" ]); }; - leadingWhitespace = true; - readLanguage = false; - readFlags = false; - readBody = false; - } - (stringToCharacters text)).acc; + in + (foldl' + parseToken + { + 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` # 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"); language = toLower block.language; in - elem language [ "elisp" "emacs-lisp" ] - && elem tangle [ "yes" ''"yes"'' ]) + elem language [ "elisp" "emacs-lisp" ] + && elem tangle [ "yes" ''"yes"'' ]) (parseOrgModeBabel text); - in - foldl' - (result: codeBlock: - result ++ (tokenizeElisp' { - elisp = codeBlock.body; - inherit (codeBlock) startLineNumber; - }) - ) - [] - codeBlocks; + in + foldl' + (result: codeBlock: + result ++ (tokenizeElisp' { + elisp = codeBlock.body; + inherit (codeBlock) startLineNumber; + }) + ) + [ ] + codeBlocks; tokenizeOrgModeBabelElisp = tokenizeOrgModeBabelElisp' { diff --git a/nix/factory.nix b/nix/factory.nix index 34ddef5..d72e13f 100644 --- a/nix/factory.nix +++ b/nix/factory.nix @@ -13,10 +13,15 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -{ lib, stdenv, emacs29, callPackage, writeShellApplication, noether -, emacsParams ? {}, - fg42Params ? {} -} : +{ lib +, stdenv +, emacs29 +, callPackage +, writeShellApplication +, noether +, emacsParams ? { } +, fg42Params ? { } +}: let lemacs = emacs29.override ({ withTreeSitter = true; @@ -44,7 +49,8 @@ let runtimeInputs = [ fg42 ]; 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; } diff --git a/nix/fg42.nix b/nix/fg42.nix index 874b6c2..97c126d 100644 --- a/nix/fg42.nix +++ b/nix/fg42.nix @@ -13,22 +13,49 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -{ lib, stdenv, elispPkgs, srcDir, emacsPackagesFor, ourPackages, direnv -, makeFontsConf, nix - -, nil, # nix lsp server +{ lib +, stdenv +, elispPkgs +, srcDir +, emacsPackagesFor +, ourPackages +, direnv +, makeFontsConf +, nix +, nixpkgs-fmt +, nil +, # nix lsp server # python deps - python311, python3Packages, - # This is a set of system tools required for FG42 + python311 +, python3Packages +, # This is a set of system tools required for FG42 # to work. - pyright, emacs, ripgrep, git, texinfo, vazir-fonts, fira-code, nerdfonts -, fira-mono, noto-fonts, gcc, ltex-ls, bash, tree-sitter, fd -, aspellWithDicts, - - supportWM ? true, xorg, slock, - - supportPython ? true, supportVerilog ? true, svls, verilator, }: + pyright +, emacs +, ripgrep +, git +, texinfo +, vazir-fonts +, fira-code +, nerdfonts +, fira-mono +, noto-fonts +, gcc +, ltex-ls +, bash +, tree-sitter +, fd +, aspellWithDicts +, supportWM ? true +, xorg +, slock +, supportPython ? true +, supportVerilog ? true +, svls +, verilator +, +}: with builtins; let version = "4.0.0"; @@ -44,7 +71,15 @@ let dicts = aspellWithDicts (dicts: with dicts; [ en en-computers en-science ]); 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) [ # Not supported on Risc-V @@ -84,7 +119,8 @@ let ]; }; -in stdenv.mkDerivation (final: rec { +in +stdenv.mkDerivation (final: rec { inherit version; pname = "fg42"; src = srcDir; diff --git a/nix/maintainers.nix b/nix/maintainers.nix index 35f0561..28f8ced 100644 --- a/nix/maintainers.nix +++ b/nix/maintainers.nix @@ -18,7 +18,7 @@ lxsameer = { email = "lxsameer@lxsameer.com"; github = "lxsameer"; - git = "lxsameer"; + git = "lxsameer"; matrix = "@lxsameer:matrix.org"; name = "Sameer Rahmani"; keys = [{ diff --git a/nix/parse.nix b/nix/parse.nix index 0edb263..30db3ff 100644 --- a/nix/parse.nix +++ b/nix/parse.nix @@ -22,76 +22,77 @@ let (x: builtins.typeOf x == "string") (builtins.split _sep _s); -in { - elispStr +in +{ elispStr , alwaysEnsure ? false }: - let - inherit (import ./elisp_reader.nix { inherit lib; }) fromElisp; +let + inherit (import ./elisp_reader.nix { inherit lib; }) fromElisp; - readFunction = fromElisp; - find = item: list: - if list == [] then [] else - if builtins.head list == item then - list - else - find item (builtins.tail list); + readFunction = fromElisp; + find = item: list: + if list == [ ] then [ ] else + if builtins.head list == item then + list + else + find item (builtins.tail list); - getKeywordValue = keyword: list: + getKeywordValue = keyword: list: + let + keywordList = find keyword list; + in + if keywordList != [ ] then let - keywordList = find keyword list; + keywordValue = builtins.tail keywordList; in - if keywordList != [] then - let - 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 + if keywordValue != [ ] then + builtins.head keywordValue else - []; - in lib.flatten (map recurse (readFunction elispStr)) + 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 + [ ]; +in +lib.flatten (map recurse (readFunction elispStr))