Create a modular Nix system to build FG42

This commit is contained in:
Sameer Rahmani 2024-04-13 22:21:20 +01:00
parent 1a0f2a31d2
commit 426c1d2dd1
Signed by: lxsameer
GPG Key ID: 8741FACBF412FFA5
14 changed files with 1208 additions and 55 deletions

219
nix/fg42/#derivation.nix# Normal file
View File

@ -0,0 +1,219 @@
# 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/>.
{ lib
, config
, stdenv
, git
, texinfo
, gcc
, bash
, utils
, emacsPackagesFor
, makeFontsConf
, xorg
, maintainers
, writeText
, writeShellApplication
, ...
}:
with builtins;
let
cfg = config.fg42;
emacs = cfg.emacs;
version = cfg.version;
emacsBundle = (emacsPackagesFor emacs).withPackages (_: cfg.elispPackages);
paths = map (x: "${x}/bin/") cfg.paths;
pathsStr = lib.strings.concatStrings (lib.strings.intersperse ":" paths);
mimeTypes = builtins.concatStringsSep ";" cfg.mimeTypes;
fontsConf = makeFontsConf { fontDirectories = cfg.fonts; };
# Whatever that needs to be in the PATH is considered a runtime
# dependency.
# Fonts are obviously runtime dependency as well
runtimeDependencies = cfg.paths ++ cfg.fonts ++ cfg.elispPackages;
buildConfig = generateBuildConfig cfg.buildConfig;
addToList = epkg: ''(add-to-list 'directories-to-autogen "${epkg}")'';
sexprs = [
''
(require 'loaddefs-gen)
(defvar directories-to-autogen '())
(defvar output-file (getenv "LOADEF_OUTPUT"))
''
] ++ (map addToList cfg.elispPackages) ++ [
''
(message ">> %s ----- %s" directories-to-autogen output-file)
(loaddefs-generate directories-to-autogen
output-file)
(provide 'loaddef-generator)
''
];
loaddefGenerator = writeText "loaddef-generator.el" (concatStringsSep "\n" sexprs);
loaddefScript = writeShellApplication {
name = "loaddef";
text = ''
#!${stdenv.shell}
set +x
LOADEF_OUTPUT="$1" ${emacsBundle}/bin/emacs -Q -q --batch -l ${loaddefGenerator}
'';
};
startupPackage = cfg.startUp;
# elsipFiles = map (file: ) cfg.elispPackages;
# nativeCompiler = epkgs: ''
# emacs -L . --batch -f batch-native-compile ${elispFiles}
# '';
in
stdenv.mkDerivation rec {
inherit version;
pname = "FG42";
src = ../../.;
buildPhase = ''
runHook preBuild
LISPDIR=$out/share/fg42/
mkdir -p $out/bin
mkdir -p $out/share/applications/
install -d $LISPDIR
cp -rv ${src}/share $out/
cp -rv ${src}/snippets $LISPDIR/snippets
cp "${fontsConf}" $LISPDIR/fonts.conf
chmod 755 $LISPDIR -R
export FONTCONFIG_FILE="$LISPDIR/fonts.conf"
cat >> $out/share/applications/FG42.desktop << EOF
[Desktop Entry]
Encoding=UTF-8
Name=FG42
GenericName=FG42
Comment=The nix base Emacs bundle for advance users
MimeType=${mimeTypes}
Type=Application
Terminal=false
Categories=Development;TextEditor;
StartupWMClass=FG42
Exec=${placeholder "out"}/bin/fg42
Icon=fg42
Version=${version}
EOF
cat >> $out/share/runtime_deps << EOF
${lib.strings.concatLines runtimeDependencies}
${emacsBundle}
EOF
cd $LISPDIR
#compile stuff
cd -
cat >> $out/bin/fg42 << EOF
#!${stdenv.shell}
export PATH=${pathsStr}:$PATH
export FONTCONFIG_FILE="$LISPDIR/fonts.conf"
LIBRARY_PATH="\$(${stdenv.cc}/bin/cc -print-file-name=libgccjit.so):\$LIBRARY_PATH" \
FG42_WM=fales ${emacsBundle}/bin/emacs \
--name FG42 \
-q --no-splash --title FG42 \
-l ${cfg.startUp} "\$@"
EOF
chmod +x $out/bin/fg42
LISPDIR=$out/share/fg42/lisp/
mkdir -p $LISPDIR
#emacs --batch -l package --eval "(package-generate-autoloads \"${pname}\" \"$LISPDIR\")"
# ${loaddefScript}/bin/loaddef ${placeholder "out"}/share/fg42/lisp/loaddefs.el
runHook postBuild
cat >> $out/bin/fg42-wm << EOF
#!${stdenv.shell}
export FG42_HOME=${placeholder "out"}/share/fg42/
export FG42_EMACSD=~/.fg42/v4/emacs.d
export FG42_USE_NIX=true;
export PATH=${pathsStr}:\$PATH
export FONTCONFIG_FILE="$LISPDIR/fonts.conf"
# Disable access control for the current user.
${xorg.xhost}/bin/xhost +SI:localuser:\$USER
# Make Java applications aware this is a non-reparenting window manager.
export _JAVA_AWT_WM_NONREPARENTING=1
# Set default cursor.
xsetroot -cursor_name left_ptr
# Set keyboard repeat rate.
xset r rate 400 30
# Uncomment the following block to use the exwm-xim module.
# export XMODIFIERS=@im=exwm-xim
# export GTK_IM_MODULE=xim
# export QT_IM_MODULE=xim
# export CLUTTER_IM_MODULE=xim
LIBRARY_PATH="\$(${stdenv.cc}/bin/cc -print-file-name=libgccjit.so):\$LIBRARY_PATH" \
FG42_WM=true ${emacsBundle}/bin/emacs \
--name FG42 \
-q --no-splash --title FG42 \
-l \$FG42_HOME/lisp/fg42/fg42.el "\$@"
EOF
chmod +x $out/bin/fg42-wm
runHook postBuild
'';
buildInputs = [ emacs emacsBundle git texinfo gcc bash ];
addEmacsNativeLoadPath = true;
meta = {
broken = false;
platforms = emacs.meta.platforms;
homepage = "https://fg42.org/";
maintainers = [ maintainers.lxsameer ];
description = "The mighty editor for the Emacsians";
longDescription = ''
FG42 is a framework to create and editor and window manager based on GNU/Emacs.
It has a pre-defined setup as well which can be installed out of the box. But the
goal of this project is to provide the API necessary to create an integrated editor.
So you need to know about Emacs in advance.
'';
license = lib.licenses.gpl3Plus;
};
}

1
nix/fg42/.#derivation.nix Symbolic link
View File

@ -0,0 +1 @@
lxsameer@majin.69922:1712871165

View File

@ -30,14 +30,20 @@ let
lib = lib;
};
utils = pkgs.callPackage ./utils.nix { };
unitModule = import ./unit.nix { inherit pkgs lib; };
final = lib.evalModules {
modules = [ unitModule ] ++ fg42Modules ++ extraModules;
specialArgs = {
inherit utils;
inherit (utils) makeFG42Drv;
};
};
in
pkgs.callPackage ./derivation.nix {
inherit (final) config options;
inherit utils;
maintainers = import ../maintainers.nix;
utils = pkgs.callPackage ./utils.nix { };
}

View File

@ -25,8 +25,11 @@
, makeFontsConf
, xorg
, maintainers
, writeText
, writeShellApplication
, ...
}:
with builtins;
let
cfg = config.fg42;
@ -42,8 +45,49 @@ let
fontsConf = makeFontsConf { fontDirectories = cfg.fonts; };
# Whatever that needs to be in the PATH is considered a runtime
# dependency.
# Fonts are obviously runtime dependency as well
runtimeDependencies = cfg.paths ++ cfg.fonts ++ cfg.elispPackages;
buildConfig = generateBuildConfig cfg.buildConfig;
addToList = epkg: ''(add-to-list 'directories-to-autogen "${epkg}")'';
sexprs = [
''
(require 'loaddefs-gen)
(defvar directories-to-autogen '())
(defvar output-file (getenv "LOADEF_OUTPUT"))
''
] ++ (map addToList cfg.elispPackages) ++ [
''
(message ">> %s ----- %s" directories-to-autogen output-file)
(loaddefs-generate directories-to-autogen
output-file)
(provide 'loaddef-generator)
''
];
loaddefGenerator = writeText "loaddef-generator.el" (concatStringsSep "\n" sexprs);
loaddefScript = writeShellApplication {
name = "loaddef";
text = ''
#!${stdenv.shell}
set +x
LOADEF_OUTPUT="$1" ${emacsBundle}/bin/emacs -Q -q --batch -l ${loaddefGenerator}
'';
};
startupPackage = cfg.startUp;
# elsipFiles = map (file: ) cfg.elispPackages;
# nativeCompiler = epkgs: ''
# emacs -L . --batch -f batch-native-compile ${elispFiles}
# '';
in
stdenv.mkDerivation rec {
inherit version;
pname = "FG42";
@ -51,13 +95,15 @@ stdenv.mkDerivation rec {
src = ../../.;
buildPhase = ''
runHook preBuild
LISPDIR=$out/share/fg42/
mkdir -p $out/bin
mkdir -p $out/share/applications/
install -d $LISPDIR
cp -rv ${src}/lisp/ $LISPDIR
# cp -rv ${src}/lisp/ $LISPDIR
cp -rv ${src}/share $out/
cp -rv ${src}/snippets $LISPDIR/snippets
@ -83,18 +129,18 @@ stdenv.mkDerivation rec {
Version=${version}
EOF
runHook preBuild
cat >> $out/share/runtime_deps << EOF
${lib.strings.concatLines runtimeDependencies}
${emacsBundle}
EOF
cd $LISPDIR
emacs -L . --batch -f batch-byte-compile *.el
#compile stuff
cd -
cat >> $out/bin/fg42 << EOF
#!${stdenv.shell}
export FG42_HOME=${placeholder "out"}/share/fg42/
export FG42_EMACSD=~/.fg42/v4/emacs.d
export FG42_USE_NIX=true;
export PATH=${pathsStr}:$PATH
export FONTCONFIG_FILE="$LISPDIR/fonts.conf"
@ -102,9 +148,16 @@ stdenv.mkDerivation rec {
FG42_WM=fales ${emacsBundle}/bin/emacs \
--name FG42 \
-q --no-splash --title FG42 \
-l \$FG42_HOME/lisp/fg42/init.el "\$@"
-l ${cfg.startUp} "\$@"
EOF
chmod +x $out/bin/fg42
LISPDIR=$out/share/fg42/lisp/
mkdir -p $LISPDIR
#emacs --batch -l package --eval "(package-generate-autoloads \"${pname}\" \"$LISPDIR\")"
# ${loaddefScript}/bin/loaddef ${placeholder "out"}/share/fg42/lisp/loaddefs.el
runHook postBuild
cat >> $out/bin/fg42-wm << EOF
@ -137,23 +190,15 @@ stdenv.mkDerivation rec {
LIBRARY_PATH="\$(${stdenv.cc}/bin/cc -print-file-name=libgccjit.so):\$LIBRARY_PATH" \
FG42_WM=true ${emacsBundle}/bin/emacs \
--name FG42 \
-q --no-splash --title FG42 \
-l \$FG42_HOME/lisp/fg42/init.el "\$@"
-q --no-splash --title FG42 \
-l \$FG42_HOME/lisp/fg42/fg42.el "\$@"
EOF
chmod +x $out/bin/fg42-wm
LISPDIR=$out/share/fg42/lisp/
emacs --batch -l package --eval "(package-generate-autoloads \"${pname}\" \"$LISPDIR\")"
runHook postBuild
'';
# installPhase = ''
# runHook preInstall
# runHook postInstall
# '';
buildInputs = [ emacs emacsBundle git texinfo gcc bash ];
addEmacsNativeLoadPath = true;

View File

@ -59,7 +59,6 @@ with lib;
A list of mineType strings that FG42 should handle via
desktop file.
'';
};
fg42.fonts = mkOption {
@ -69,6 +68,12 @@ with lib;
A list of font packages that should be included in FG42
'';
};
fg42.startUp = mkOption {
type = types.uniq types.path;
description = "The main startup file to load first. This is usually fg42.el";
};
};

View File

@ -13,7 +13,26 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
{ ... }:
{ emacsPackages, writeTextFile, ... }:
{
makeDesktopFile = { };
makeFG42Drv = { pname, version, ... }@args:
(emacsPackages.trivialBuild args).overrideAttrs (old: {
pname = "fg42-${pname}";
installPhase = ''
runHook preInstall
LISPDIR=$out/share/emacs/
install -d $LISPDIR
cp -rv lisp/ $LISPDIR/site-lisp
emacs --batch -l package --eval "(package-generate-autoloads \"${args.pname}\" \"$LISPDIR/site-lisp\")"
runHook postInstall
'';
});
}

View File

@ -0,0 +1,122 @@
# 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/>.
# This is the home manager module that exposes FG42. It differs
# from FG42 modules that are structurally the same but used in
# different context
# A list of default FG42 modules to build FG42 with.
{ lib, config, pkgs, ... }:
with lib;
let
generateBuildConfig = configs:
let
defineConfig = cs: name:
let
config = builtins.getAttr name cs;
form = if config.const then "defconst" else "defvar";
in
''(${form} ${name} ${config.value} "${config.docs}")'';
configsList = builtins.map (defineConfig configs) (builtins.attrNames configs);
in
pkgs.writeTextFile {
name = "build-config";
text = ''
${builtins.concatStringsSep "\n" configsList}
(provide 'fg42/build-config)
'';
executable = false;
};
buildConfig = generateBuildConfig (config.fg42.buildConfig);
drv = pkgs.emacsPackages.trivialBuild rec {
pname = "fg42-build-config";
version = config.fg42.version;
src = ./.;
buildPhase = ''
runHook preBuild
LISPDIR=$out/share/emacs/site-lisp/fg42
install -d $LISPDIR
cp -v ${buildConfig} $LISPDIR/build-config.el
emacs -L . --batch -f batch-byte-compile *.el
runHook postBuild
'';
installPhase = ''
runHook preInstall
LISPDIR=$out/share/emacs/site-lisp/fg42/
emacs --batch -l package --eval "(package-generate-autoloads \"${pname}\" \"$LISPDIR\")"
runHook postInstall
'';
};
in
{
options = {
fg42.buildConfig = mkOption {
type = types.attrsOf
(types.submodule {
options = {
value = mkOption {
type = types.str;
default = "nil";
description = ''
The value should be quoted. For example the string "nil"
means the actual nil in elisp and the string "\"foo\""
means elisp string "foo".
'';
};
docs = mkOption {
type = types.str;
description = "The docstring for the variable or constant (mandatory)";
};
const = mkOption {
type = types.bool;
default = false;
description = "defvar vs defconst";
};
};
});
default = { };
example = ''
fg42.config = {
"fg42/some-var" = {
value = "foo";
docs = "The docstring";
const = false;
};
};
'';
description = ''
An attrset of configuration variables and their values
that should end up in `fg42/config` elisp module.
'';
};
};
config = {
fg42.elispPackages = [ drv ];
};
}

View File

@ -22,7 +22,8 @@
{ pkgs, lib }:
let
modules = [
./editor.nix
./build_config
./editor
];
pkgsModule = { config, ... }: {

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/>.
# This is the home manager module that exposes FG42. It differs
# from FG42 modules that are structurally the same but used in
# different context
# A list of default FG42 modules to build FG42 with.
{ lib, ... }:
{
options = {
fg42.editor = lib.mkOption {
type = lib.types.str;
default = "blah";
description = ''
FG42's version1.
'';
};
};
}

View File

@ -0,0 +1,79 @@
# 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/>.
# This is the home manager module that exposes FG42. It differs
# from FG42 modules that are structurally the same but used in
# different context
# A list of default FG42 modules to build FG42 with.
{ lib, config, pkgs, makeFG42Drv, ... }:
let
deps = (with pkgs.emacsPackages; [
origami
which-key
projectile
projectile-ripgrep
pkg-info
expand-region
helpful
envrc
pinentry
discover
exec-path-from-shell
avy
ace-window
yasnippet
yasnippet-snippets
flycheck
]);
drv = makeFG42Drv {
pname = "fg42-editor";
version = config.fg42.version;
buildInputs = deps;
src = ./.;
};
dicts = pkgs.aspellWithDicts (dicts: with dicts; [ en en-computers en-science ]);
in
{
config = {
fg42.elispPackages = [ drv ] ++ deps;
fg42.startUp = lib.mkDefault "${drv}/share/emacs/site-lisp/fg42.el";
fg42.fonts = (with pkgs;[
vazir-fonts
fira-code
fira-mono
noto-fonts
]);
fg42.paths = (with pkgs;[
ripgrep
dicts
]);
fg42.buildConfig = {
"fg42/font" = {
value = '''("Fira Mono" 11)'';
docs = ''
The default font for FG42. You can override it
in your configuration file.
'';
};
};
};
}

View File

@ -0,0 +1,166 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani <lxsameer@gnu.org>
;;
;; 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:
(require 'fg42/utils)
(eval-when-compile
(defvar package-archives)
(defvar use-package-ensure-function))
;; ============================================================================
;; Basic inital configuration for FG42's operations
;; ============================================================================
(defgroup fg42 nil
"Customize your FG42 instance via this group of configurations."
:group :editor)
(defvar fg42/disabled-features nil
"List of features to disable.")
(defvar fg42/after-init-hook nil
"The hook tha runs when FG42 finished running the user configuration.")
(defvar fg42/debug? nil
"It is t If FG42 is running in debug mode and nil otherwise.")
(defvar fg42/-gc-cons-threshold 16777216
"Value of GC threshold of FG42.")
(defvar fg42/initialized nil
"A variable that indicates whether FG42 is passed initialization.")
(defconst fg42/cache-dir (or (getenv "FG42_CACHE_DIR")
(path-join (or (getenv "XDG_CACHE_HOME") "~/.cache")
"fg42")))
(defconst fg42/config-dir (or (getenv "FG42_CONFIG_DIR")
(path-join (or (getenv "XDG_CONFIG_HOME") "~/.config")
"fg42")))
(defun defer-garbage-collection ()
"Disable garbage collection."
(setq gc-cons-threshold fg42/-gc-cons-threshold))
(defun restore-garbage-collection ()
"Restore garbage collection to it's default value."
(run-at-time
1 nil (lambda () (setq gc-cons-threshold most-positive-fixnum))))
(defun fg42/-startup-optimization ()
"Optimized FG42 startup."
;; by setting gc threshold to the largest number
;; Emacs can understand we are basically disabling it :).
(setq gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.6)
;; after initilization phase restore cons threshold to normal
(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-threshold fg42/-gc-cons-threshold ; 16mb
gc-cons-percentage 0.1)))
;; disable gc when we are in minibuffer using the same method we
;; use for initilization time
(add-hook 'minibuffer-setup-hook #'defer-garbage-collection)
;; just enable gc when exiting minibuffer
(add-hook 'minibuffer-exit-hook #'restore-garbage-collection)
;; we dont need Emacs to check every file type and look for file
;; handlers when we are initializing so we backup the original
;; value and set it to nil
(setq --file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)
;; after initialization we can restore that file-name-handler-alist
;; to original value.
(add-hook 'emacs-startup-hook
(lambda ()
(setq file-name-handler-alist
--file-name-handler-alist)))
;; initial mode for emacs can be fundamental mode we have nothing to lose
(setq initial-major-mode 'fundamental-mode))
(defun fg42/initialize ()
"Initialize FG42 after the Emacs window is rendered by loading the user init file."
;; (fg42/-startup-optimization)
(require 'fg42/editor)
(when (file-exists-p user-init-file)
(load user-init-file))
(fg42/setup-editor)
;; ;; If user didn't select a theme, load the default stuff
;; (when (not (featurep 'fg42/themes))
;; (require 'fg42/themes))
(add-hook 'emacs-startup-hook
(lambda ()
(run-hooks 'fg42/after-init-hook)
(run-hooks 'fg42/ui-hook)
(setq fg42/initialized t))))
(defun fg42/main ()
"The entry point of FG42."
(when (string= (getenv "FG42_DEBUG") "1")
(setq debug-on-error t
fg42/debug? t))
;; We don't use any Emacs package manager, so
;; prevent package.el to install anything at startup
(setq package-enable-at-startup nil
package-archives nil
use-package-ensure-function 'ignore
;; Setup the path for the custom.el file, We don't want
;; to touch user's Emacs configuration.
custom-file (path-join fg42/config-dir "custom.el")
;; Change the config dir to `~/.config/fg42/' by default
;; again, we don't want to temper with user's Emacs
user-emacs-directory fg42/config-dir
user-init-file
(or (getenv "FG42_CONFIG_FILE")
(path-join fg42/config-dir "fg42.el")))
;; Change the eln file cache to leave Emacs alone.
(startup-redirect-eln-cache
(or (getenv "FG42_ELN_DIR")
(path-join fg42/cache-dir "fg42.el")))
;; Load the customization file. In FG42 it is different than
;; the default `user-init-file'
(if (file-exists-p custom-file)
(load custom-file))
;; From point forward we can use normal Elisp stuff without
;; interfering with user's Emacs configuration
(fg42/initialize))
(fg42/main)
(provide 'fg42)
;;; fg42.el ends here

View File

@ -0,0 +1,293 @@
;;; 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)
;; We build this file via the main FG42's Nix derivation. It
;; contains the final Nix configuration of FG42.
(require 'fg42/build-config)
;; ;; Language support
;; (require 'fg42/autocomplete)
;; (require 'fg42/langs/langs)
;; (require 'fg42/eglot)
;; (require 'fg42/langs/cpp)
;; (require 'fg42/langs/verilog)
;; (require 'fg42/langs/python)
;; (require 'fg42/langs/elisp)
;; (require 'fg42/langs/nix)
;; (require 'fg42/git)
;; (require 'fg42/wm)
;; (require 'fg42/org)
;; (require 'fg42/minibuffer)
;; (require 'fg42/graphics)
;; (require 'fg42/modeline)
)
(require 'server)
(require 'fg42/utils)
(defun fg42/setup-font ()
"Set the default font of `FG42' to FONT-NAME and FONT-SIZE."
(let ((name (car fg42/font))
(size (cadr fg42/font)))
(add-to-list 'default-frame-alist
(cons 'font (format "%s-%d" name size)))
(set-face-attribute 'default t :font name)))
(defun fg42/setup-editor ()
"Setup the overall functionality of FG42."
(use! origami
"A text folding minor mode for Emacs."
:bind
(("C-c TAB" . origami-toggle-node))
:config
(global-origami-mode t))
(use! which-key
"which-key is a minor mode for Emacs that displays the key bindings following
your currently entered incomplete command (a prefix) in a popup. For example,
after enabling the minor mode if you enter ~C-x~ and wait for the default of
1 second the minibuffer will expand with all of the available key bindings
that follow ~C-x~ (or as many as space allows given your settings).
This includes prefixes like ~C-x 8~ which are shown in a different face."
:config
(which-key-setup-side-window-bottom)
(which-key-mode))
(use! projectile
"Projectile is a project interaction library for Emacs. Its goal is to provide
a nice set of features operating on a project level without introducing
external dependencies."
:hook (emacs-startup . projectile-mode)
:config
;; We don't want the auto discovery on startup
(setq projectile-auto-discover nil)
(setq projectile-enable-caching t)
:bind (:map projectile-mode-map
("s-p" . projectile-command-map)
("C-c p" . projectile-command-map)))
(use! projectile-ripgrep
"Use ripgrep with projectile"
:after projectile)
(use! pkg-info
"`pkg-info' integration.")
(use! expand-region
"Expand region increases the selected region by semantic units.
Just keep pressing the key until it selects what you want."
:bind ("C-=" . er/expand-region))
(use! helpful
"Helpful is an alternative to the built-in Emacs help that provides much more
contextual information."
:bind
(("C-h f" . helpful-callable)
("C-h v" . helpful-variable)
("C-h k" . helpful-key)
("C-h x" . helpful-command)
("C-c C-d" . helpful-at-point)))
(use! envrc
"Activate direnv whenever encounter a `.envrc' file"
:config
(envrc-global-mode))
(use! pinentry
"Pinentry cube with setup the =pinentry= program to be used within FG42."
:commands pinentry-start
:init
(setq epa-pinentry-mode 'loopback))
(use! imenu-list
"his Emacs minor-mode creates an automatically updated buffer
called `Ilist' that is populated with the current buffer's imenu entries.
The `Ilist' buffer is typically shown as a sidebar (Emacs vertically splits the window)."
:bind (("C-'" . imenu-list-smart-toggle)))
(use! discover
"Adds support for the discover.el `https://github.com/mickeynp/discover.el'.")
(use! exec-path-from-shell
"This package fixes the =exec-path-from-shell= issue on MacOS."
:config
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize)))
(use! hl-line
"Highlights the current line."
:hook (emacs-startup . global-hl-line-mode))
(use! avy
"This cube controls the different aspect of buffer navigation"
:bind ("M-1" . avy-goto-word-1))
(use! ace-window
"This cube controls the different aspect of buffer navigation"
:bind ("C-<tab>" . ace-window))
(when-not-wm
(use! flyspell
"Spell checking on the fly"
:commands (flyspell-mode flyspell-prog-mode)
:init
(setq-default ispell-program-name "aspell")
(setq-default ispell-extra-args '("--sug-mode=ultra"
"--lang=en_US"
"--camel-case")))
(use! savehist
"Persist history over Emacs restarts. Vertico sorts by history position."
:init
(savehist-mode))
(use! display-line-numbers
"The builtin replacement of linum. It's is pretty fast."
:config
(global-display-line-numbers-mode 1)))
(use! yasnippet
"A Snippet is a template system for Emacs. "
:config
(let* ((snippet-home
(path-join
(file-name-directory
(locate-library "yasnippet-snippets")) "snippets"))
(local-snippet (path-join (file-name-directory
(locate-library "fg42")) "../snippets"))
(user-snippets (path-join fg42/config-dir "snippets")))
(setq yas-snippet-dirs `(,user-snippets ,local-snippet ,snippet-home))
(yas-global-mode 1)))
(use! yasnippet-snippets
"Yasnippet's snippets."
:after yasnippet)
(use! flycheck
"Flycheck is a modern on-the-fly syntax checking extension for GNU Emacs."
:config (global-flycheck-mode))
;; In the following section we're setting some default behavior of FG42.
;; Most of these configuration are opiniated and I think most of people
;; shared the same opinion or don't care at all.
(fg42/setup-font)
(add-hook 'fg42/after-init-hook
(lambda ()
(set-default 'cursor-type 'bar)
(set-cursor-color "#eeeeec")))
;; Remove splash screen
(setq inhibit-splash-screen t)
;; scratch should be scratch
(setq initial-scratch-message nil)
;; Don't allow tab as indent
(setq-default indent-tabs-mode nil)
;; Default indent width
(setq tab-width 2)
;; Share the clipboard with X applications
(setq x-select-enable-clipboard t)
;; Automatically removed excess backups of the file
(setq delete-old-versions t)
;; Emacs 28 and newer: Hide commands in M-x which do not work in the current
;; mode. Vertico commands are hidden in normal buffers. This setting is
;; useful beyond Vertico.
(setq read-extended-command-predicate #'command-completion-default-include-p)
;; Support opening new minibuffers from inside existing minibuffers.
(setq enable-recursive-minibuffers t)
(setq tooltip-use-echo-area t)
(setq x-gtk-use-system-tooltips nil)
;; Global configurations
(tool-bar-mode -1)
(tooltip-mode nil)
(menu-bar-mode -1)
(when (display-graphic-p)
;; Smoother scrolling
(pixel-scroll-precision-mode)
(scroll-bar-mode -1))
(defalias 'yes-or-no-p 'y-or-n-p)
;; Hooks ---
(add-hook
'emacs-startup-hook
(lambda ()
;; It only applies to toolkit=no
(set-mouse-color (get-base16-color-or :base07 "#eeeeec"))
;; Switch from `dabbrev-expand' to `hippie-expand'
(global-set-key [remap dabbrev-expand] 'hippie-expand)
(column-number-mode t)
(show-paren-mode t)
(electric-pair-mode 1)
;; Rectangular select
(cua-selection-mode t)
;; Yank the region on type
(delete-selection-mode 1)))
;; Deletel extra trailing white spaces on save
(add-hook 'before-save-hook 'delete-trailing-whitespace)
;; Enable rainbow-delimiters for programming
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
;; With this section we will have two emacs server running
;; this way we can interact with the wm via emacsclient as well
(when (not (server-running-p))
(when-wm
(setq server-name "fg42-wm"))
(server-start)
(require 'org-protocol))
(when-wm
;; Activating the WM mode
(exwm-enable)
(exwm-systemtray-enable)
(exwm-randr-enable))
(message "[FG42]: Use `fg42-help' to get help."))
(provide 'fg42/editor)
;;; editor.el ends here

View File

@ -0,0 +1,161 @@
;;; Utils --- Utils library of FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani <lxsameer@gnu.org>
;;
;; 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:
;; `System' is just a state monad which holds the state of the editor.
;; Each system has to have a `start' function to start the setup process.
;;
;;; Code:
(require 'cl-lib)
(autoload 'seq-partition "seq")
(autoload 'cl-reduce "cl-seq")
(defun buffer-mode (buffer-or-string)
"Return the major mode associated with a the given BUFFER-OR-STRING."
(with-current-buffer buffer-or-string
major-mode))
(defun ->buffer (buffer-name data &optional fn)
"Insert the given DATA into the given buffer provided by BUFFER-NAME.
It will create a the buffer if it doesn't exist. It will call the given FN
at the end in context of the buffer. This function accepts only one argument
with is the buffer."
(let ((buf (get-buffer-create buffer-name)))
(with-current-buffer buf
(insert data)
(when fn
(funcall fn buf)))))
(defun ->str (&rest args)
"Convert the given ARGS into string."
(funcall #'pp-to-string args))
(defmacro inspect-expression (&rest body)
"Pretty prints the result of the given BODY."
`(pp-display-expression ,@body (get-buffer-create fg42/inspect-buffer)))
(defun inspect-data-append (data)
"Append the given DATA to the inspection buffer with padding."
;; TODO: Move 'fg42/inspect-buffer' to the somewhere propriate
;; possiblly the system.
(->buffer
"fg42/inspect-buffer"
(format
"\n;; START ======================================================\n%s%s"
(pp-to-string data)
";; END.\n")))
(defun apply-face (face-symbol text)
"Apply the given FACE-SYMBOL to the given TEXT."
(put-text-property 0 (length text) 'face face-symbol text))
(defmacro comment (&rest _body)
"A macro similar to Clojure's comment macro that ignore the BODY."
(declare (indent 0))
`nil)
(defmacro debug-message (&rest params)
"Print out the given PARAMS only if debug mode is on."
(if debug-on-error
`(message ,@params)
nil))
(defmacro deprecated (msg &rest form)
"Mark the given FORM as deprecated with the given MSG."
(declare (indent 0))
`(progn
(warn (format "[DEPRECATED]: %s" ,msg))
,@form))
(defun path-join (&rest paths)
"Join the given PATHS."
(apply #'concat
(append
(mapcar #'file-name-as-directory (butlast paths))
(last paths))))
(defmacro -> (x &optional form &rest more)
"Thread the expr through the forms FORM and rest of form in MORE.
Insert X as the second item in the first form, making a list of
it if it is not a list already. If there are more forms, insert
the first form as the second item in second form, etc."
(declare (debug (form &rest [&or symbolp (sexp &rest form)])))
(cond
((null form) x)
((null more) (if (listp form)
`(,(car form) ,x ,@(cdr form))
(list form x)))
(:else `(-> (-> ,x ,form) ,@more))))
(defmacro ->> (x &optional form &rest more)
"Thread the expr through the forms FORM and the rest at MORE.
Insert X as the last item in the first form, making a list of
it if it is not a list already. If there are more forms, insert
the first form as the
last item in second form, etc."
(declare (debug ->))
(cond
((null form) x)
((null more) (if (listp form)
`(,@form ,x)
(list form x)))
(:else `(->> (->> ,x ,form) ,@more))))
(defmacro when-wm (&rest body)
"Run the BODY only if in wm mode."
(if (string= (getenv "FG42_WM") "true")
`(progn ,@body)
nil))
(defmacro when-not-wm (&rest body)
"Run the BODY only if not in the wm mode."
(if (not (string= (getenv "FG42_WM") "true"))
`(progn ,@body)
nil))
(defun get-base16-color-or (color-name default)
"Return the color for COLOR-NAME if a base16 theme is loade otherwise DEFAULT."
(let* ((theme (car custom-enabled-themes))
(theme-sym (intern (format "%s-theme-colors" theme))))
(if (boundp theme-sym)
(or (eval `(plist-get ,theme-sym ,color-name)) default)
default)))
(provide 'fg42/utils)
;;; utils.el ends here

View File

@ -0,0 +1,69 @@
;;; fpkg --- a simple package manager for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2010-2024 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; Keywords: lisp fg42 IDE package manager
;; Version: 1.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:
;;
;; Simple package manager for FG42
;;
;;; Code:
(require 'map)
(defvar package-names ())
(eval-when-compile
(defvar fg42/disabled-features '())
(require 'use-package))
(defun inject-params (args)
"Inject required `use-package' params to ARGS if the key is missing."
;; (if (member :defer args)
;; (append '(:ensure nil) args)
(append args '(:ensure nil)))
(defmacro fpkg/use (pkg &rest details)
"Install the given package DETAILS PKG via `use-package' and straight."
(declare (indent defun))
(if (and (listp details) (< 0 (length details)))
(let ((p (inject-params details)))
`(progn
(use-package ,pkg ,@p)))
`(progn
(use-package ,pkg :defer t :ensure nil))))
(defmacro use! (pkg docs &rest details)
"Loading the given package DETAILS PKG via `use-package'.
DOCS is the documentation of the package."
(declare (indent defun) (doc-string 2))
(when (not (stringp docs))
(error "Missing docstring for '%s' package" pkg))
(let ((disabled (or (member pkg fg42/disabled-features) nil)))
(when (not disabled)
`(use-package ,pkg ,@details))))
(provide 'fpkg)
;;; fpkg.el ends here