diff --git a/.gitignore b/.gitignore index b1409d6..41255ae 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ nohup.out lib/**/*.elc *.elc tmp/ -test-runner/ \ No newline at end of file +test-runner/ +.fpkg/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..4e32ab6 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,31 @@ +stages: + - build + +.build: + image: debian:stable-slim + stage: build + before_script: + - apt update && apt install -y make wget git emacs sudo + - git clone -b fpkg-v2 https://gitlab.com/FG42/FG42 ~/.fg42/ && cd ~/.fg42/ && make install && + script: + - cd ~/.fg42/ && fg42 -nw --script build.el + +build-branches: + extends: .build + only: + - branches + except: + - tags + +build-package: + extends: .build + script: + - cd /root/.fg42/ && fg42 -nw --script build.el + - tar zcf ~/fg42.$CI_COMMIT_TAG.tar.gz ~/.fg42/ + - mv ~/fg42.$CI_COMMIT_TAG.tar.gz /builds/$CI_PROJECT_PATH/ + artifacts: + when: on_success + paths: + - fg42.$CI_COMMIT_TAG.tar.gz + only: + - tags diff --git a/Makefile b/Makefile index 667102f..e538a7d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,22 @@ +.PHONY: update update: @git remote set-url origin git://gitlab.com/FG42/FG42.git @git pull origin master + +.PHONY: install-cli +install-ci: + @echo "Downloading and installing fonts..." + @mkdir -p ~/.fonts + @wget "https://github.com/FG42/fonts/archive/0.1.0.tar.gz" -O ~/.fonts/fg42.tar.gz + @tar zxf ~/.fonts/fg42.tar.gz -C ~/.fonts --strip 1 + @cp ./config/fg42.user.el ${HOME}/.fg42.el + @echo "Creating the link..." + @echo "#! /bin/sh" > ./fg42 + @echo "export FG42_HOME=$(shell pwd)" >> ./fg42 + @echo 'emacs --name FG42 --no-site-file --no-site-lisp --no-splash --title FG42 -l $$FG42_HOME/fg42-config.el "$$@"' >> ./fg42 + @chmod +x ./fg42 + +.PHONY: install install: @echo "Downloading and installing fonts..." @mkdir -p ~/.fonts @@ -21,11 +37,8 @@ install: @echo "------------------------------------------------------------------------------------" @echo "Make sure to install external dependencies of FG42. For more info checkout README.md" @echo "Enjoy the bless of GNU/Emacs and FG42 :)" + +.PHONY: install-fonts install-fonts: @mkdir -p ~/.fonts/ @cp -rv ./share/fonts/vazir/* ~/.fonts/ -build-image: - docker build . -t fg42:1 --build-arg emacs_version=26.3 - -clean-image: - docker rmi fg42:1 diff --git a/build.el b/build.el new file mode 100644 index 0000000..8eb8c20 --- /dev/null +++ b/build.el @@ -0,0 +1,47 @@ +;;; build --- build script for FG42 +;; +;; Copyright (C) 2010-2020 Sameer Rahmani +;; +;; Author: Sameer Rahmani +;; 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 . +;; +;;; Commentary: +;;; Code: +(add-to-list 'load-path (concat (getenv "HOME") ".fg42/lib")) + +(defvar bootstrap-version nil + "Bootstrap version of straight. This var is used in straight's installer.") + +(defun fpkg-initialize () + "Initilize the straight.e package manager and setup necessary hooks." + (let ((bootstrap-file "~/.fg42/.fpkg/straight/repos/straight.el/bootstrap.el") + (bootstrap-version 5)) + + (setq straight-base-dir "~/.fg42/.fpkg/") + (if (not (file-exists-p bootstrap-file)) + (with-current-buffer + (url-retrieve-synchronously + "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" + 'silent 'inhibit-cookies) + (goto-char (point-max)) + (eval-print-last-sexp)) + (load bootstrap-file nil 'nomessage)))) + +(fpkg-initialize) + +(provide 'build) +;;; build.el ends here diff --git a/config/fg42.user.el b/config/fg42.user.el index aca9dd7..23bb7c7 100644 --- a/config/fg42.user.el +++ b/config/fg42.user.el @@ -37,6 +37,7 @@ 'arduino 'java 'racket + 'devops 'irc 'latex) diff --git a/lib/extensions/development.el b/lib/extensions/development.el index d0560c0..53b4faf 100644 --- a/lib/extensions/development.el +++ b/lib/extensions/development.el @@ -9,7 +9,7 @@ (depends-on 'yasnippet) (depends-on 'yasnippet-snippets) (depends-on 'smart-mode-line) -(depends-on 'dockerfile-mode) + (depends-on 'quickrun) (depends-on 'dash) (depends-on 'websocket) @@ -34,7 +34,9 @@ (with-ability git (depends-on 'diff-hl) (depends-on 'magit) - (depends-on 'gh)) + (depends-on 'gh) + (when (is-evil?) + (depends-on 'evil-magit))) (with-ability github (depends-on 'magithub)) diff --git a/lib/extensions/development/init.el b/lib/extensions/development/init.el index 7a21d9a..f1dab33 100644 --- a/lib/extensions/development/init.el +++ b/lib/extensions/development/init.el @@ -180,7 +180,11 @@ (cheatsheet-add :group '--Development-- :key "C-x g" :description "Rise up MAGIT. Git interface for FG42") - (global-set-key (kbd "C-x g") 'magit-status)) + (global-set-key (kbd "C-x g") 'magit-status) + (when (is-evil?) + (add-hook 'magit-mode-hook (lambda () (require 'evil-magit))) + (defkey global-map 'magit-status :evil (:normal "SPC g s")))) + (ability github () "Github support" diff --git a/lib/extensions/devops.el b/lib/extensions/devops.el new file mode 100644 index 0000000..3854d1b --- /dev/null +++ b/lib/extensions/devops.el @@ -0,0 +1,19 @@ +;;; DevopsExtension --- Enable Devops support in FG42 +;;; Commentary: +;;; Code: +(require 'fpkg) +(require 'fg42/extension) +(require 'extensions/devops/init) + +;; dependencies +(depends-on 'kubel) +(depends-on 'ansible) +(depends-on 'docker) +(depends-on 'dockerfile-mode) + +(extension devops + :version 0.0.1 + :on-initialize extensions/devops-initialize + :docs "lib/extensions/devops/readme.org") +(provide 'extensions/devops) +;; devops ends here diff --git a/lib/extensions/devops/init.el b/lib/extensions/devops/init.el new file mode 100644 index 0000000..b38f84c --- /dev/null +++ b/lib/extensions/devops/init.el @@ -0,0 +1,12 @@ +;;; devops-init --- The entry point for devops extension +;;; Commentary: +;;; Code: + +(defun extensions/devops-initialize () + "Initialize devops extension." + (exec-path-from-shell-initialize) + (add-to-list 'auto-mode-alist '("Dockerfile\\'" . dockerfile-mode)) + (add-hook 'yaml-mode-hook (lambda () (ansible)))) + +(provide 'extensions/devops/init) +;;; init ends here. diff --git a/lib/extensions/editor.el b/lib/extensions/editor.el index 7f003e1..f31c6fe 100644 --- a/lib/extensions/editor.el +++ b/lib/extensions/editor.el @@ -25,9 +25,6 @@ (depends-on 'eyebrowse) -;; general for simpler keybindin -(depends-on 'general) - ;; Themes (depends-on 'spacemacs-theme) (depends-on 'doom-themes) @@ -83,6 +80,8 @@ (with-ability tabbar (depends-on 'tabbar)) +(with-ability which-key + (depends-on 'which-key)) (if (eq system-type 'darwin) (depends-on 'exec-path-from-shell)) diff --git a/lib/extensions/editor/init.el b/lib/extensions/editor/init.el index 6e0073a..fef0dfc 100644 --- a/lib/extensions/editor/init.el +++ b/lib/extensions/editor/init.el @@ -10,6 +10,14 @@ (defvar fg42-before-open-todo-hook nil) (defvar fg42-after-open-todo-hook nil) +;; Vars ----------------------------------------------------------------------- +(defvar fg42-font "Fira Mono" + "The default font to be used with FG42.") + +(defvar fg42-font-size 12 + "The default font to be used with FG42.") + + ;; Functions ------------------------------------------------- (defun fg42-reload () "Reload the entire FG42." @@ -58,10 +66,35 @@ ;; Font Configuration ----------------------------------- (ability font () "Sets the default font to fg42 font" - (add-to-list 'default-frame-alist (cons 'font fg42-font)) + (add-to-list 'default-frame-alist (cons 'font (format "%s-%d" fg42-font fg42-font-size))) (set-face-attribute 'default t :font fg42-font)) ;; ------------------------------------------------------ + (ability which-key () + (when (is-evil?) + (which-key-mode t))) + + ;; enhance evil mode with space leader keybindings + (ability space-keys (which-key) + "evil mode with space leader keybindings" + (when (is-evil?) + (defkey global-map 'find-file :evil (:normal "SPC f f")) + (defkey global-map 'kill-buffer :evil (:normal "SPC b k")) + (defkey global-map 'save-buferr :evil (:normal "SPC b s")) + (defkey global-map 'next-buffer :evil (:normal "SPC b n")) + (defkey global-map 'previous-buffer :evil (:normal "SPC b p")) + (defkey global-map 'switch-to-buffer :evil (:normal "SPC b l")) + (defkey global-map 'other-window :evil (:normal "SPC w o")) + (defkey global-map 'delete-window :evil (:normal "SPC w d")) + (defkey global-map 'delete-other-windows :evil (:normal "SPC w m")) + (defkey global-map 'split-window-vertically :evil (:normal "SPC w s v")) + (defkey global-map 'eval-last-sexp :evil (:normal "SPC e e")) + (defkey global-map 'eval-buffer :evil (:normal "SPC e b")) + (defkey global-map 'comment-line :evil (:normal "SPC l c")) + (defkey global-map 'describe-key :evil (:normal "SPC d k")) + (defkey global-map 'describe-function :evil (:normal "SPC d f")) + (defkey global-map 'describe-variable :evil (:normal "SPC d v")))) + (cheatsheet-add :group '--HELP-- :key "C-?" :description "Show this cheatsheet") @@ -97,22 +130,7 @@ (ability highligh-current-line () "Highlights the current line." (global-hl-line-mode t)) - - ;; enhance evil mode with space leader keybindings - (ability space-keys - "evil mode with space leader keybindings" - (when (is-evil?) - (general-define-key - :states '(normal visual insert emacs) - :prefix "SPC" - :non-normal-prefix "C-SPC" - "bl" 'switch-to-buffer - "ff" 'find-file - "sv" 'split-window-vertically - "sh" 'split-window-horizontally))) - - - (ability flycheck () + (ability flycheck () "Check syntax on the fly using flycheck." (require 'flycheck) diff --git a/lib/extensions/lua.el b/lib/extensions/lua.el new file mode 100644 index 0000000..860d435 --- /dev/null +++ b/lib/extensions/lua.el @@ -0,0 +1,17 @@ +;;; LuaExtention --- Enable Lua support in FG42 +;;; Commentary: +;;; Code: +(require 'fpkg) +(require 'fg42/extension) +(require 'extensions/lua/init) + +;; dependencies +(depends-on 'lua-mode) + + +(extension lua + :version 0.0.1 + :on-initialize extensions/lua-initialize + :docs "lib/extensions/lua/readme.org") +(provide 'extensions/lua) +;;; lua.el ends here diff --git a/lib/extensions/lua/init.el b/lib/extensions/lua/init.el new file mode 100644 index 0000000..9d31bd4 --- /dev/null +++ b/lib/extensions/lua/init.el @@ -0,0 +1,9 @@ +;;; lua-init --- The entry point for lua extension +;;; Commentary: +;;; Code: +(defun extensions/lua-initialize () + "Initialize lua extension.") + + +(provide 'extensions/lua/init) +;;; init ends here. diff --git a/lib/extensions/rust.el b/lib/extensions/rust.el new file mode 100644 index 0000000..d9ead04 --- /dev/null +++ b/lib/extensions/rust.el @@ -0,0 +1,17 @@ +;;; RustExtention --- Enable Rust support in FG42 +;;; Commentary: +;;; Code: +(require 'fpkg) +(require 'fg42/extension) +(require 'extensions/rust/init) + +;; dependencies +(depends-on 'rust-mode) +(depends-on 'cargo) +(depends-on 'flycheck-rust) +(extension rust + :version 0.0.1 + :on-initialize extensions/rust-initialize + :docs "lib/extensions/rust/readme.org") +(provide 'extensions/rust) +;;; rust.el ends here diff --git a/lib/extensions/rust/init.el b/lib/extensions/rust/init.el new file mode 100644 index 0000000..7d6ee7a --- /dev/null +++ b/lib/extensions/rust/init.el @@ -0,0 +1,11 @@ +;;; rust-init --- The entry point for Rust extension +;;; Commentary: +;;; Code: + +(defun extensions/rust-initialize () + "Initialize Rust extension." + (add-hook 'rust-mode-hook #'lsp) + (add-hook 'rust-mode-hook #'cargo-minor-mode) + (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)) +(provide 'extensions/rust/init) +;;; init ends here. diff --git a/lib/fg42.el b/lib/fg42.el index ad6ecc8..a873e13 100644 --- a/lib/fg42.el +++ b/lib/fg42.el @@ -29,27 +29,81 @@ (defvar fg42-tmp (concat fg42-home "/tmp")) +(require 'fpkg) +(fpkg-initialize-once) + +(require 'fg42/base) +(require 'fg42/splash) +(require 'fg42/race) +(require 'fg42/utils) +(require 'fg42/key-bindings) + + (defvar fg42-before-initialize-hook nil "This hook will be called before FG42 initilization process.") (defvar fg42-after-initialize-hook nil "This hook will be called after FG42 initilization process.") +(defvar fg42-gc-cons-threshold 16777216 + "Value of GC threshold of 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 () + "Optimize 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 auto initilization of package.el + (setq package-enable-at-startup nil) + ;; 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)) -(require 'fpkg) -(require 'fg42/base) -(require 'fg42/splash) -(require 'fg42/race) -(require 'fg42/utils) (defun fg42-initialize () "Initialize FG42 editor." + (setq fg42-start-timestamp (float-time)) + (fg42--startup-optimization) (run-hooks 'fg42-before-initialize-hook) (mkdir fg42-tmp t) (setq package-user-dir (concat fg42-home "/packages")) (fpkg-initialize) (initialize-extensions) - (run-hooks 'fg42-after-initialize-hook)) + (run-hooks 'fg42-after-initialize-hook) + (message "startup time: %s" (- (float-time) fg42-start-timestamp))) + (provide 'fg42) ;; fg42.el ends here diff --git a/lib/fg42/key-bindings.el b/lib/fg42/key-bindings.el index c590703..f7f1224 100644 --- a/lib/fg42/key-bindings.el +++ b/lib/fg42/key-bindings.el @@ -23,7 +23,6 @@ ;;; Commentary: ;;; Code: -(require 'fg42/race) (defun -defkey-god (map key fn) "Set the given KEY on key map MAP to FN." @@ -35,26 +34,37 @@ (define-key map (kbd key) fn)) -(defun -defkey-evil (map key fn) - "Set the given KEY on key map MAP to FN." - (define-key map (kbd key) fn)) +(defun -defkey-evil (map state-keys fn) + "Set the given STATE-KEYS on key map MAP to FN." + (let ((normal-key (plist-get state-keys :normal)) + (visual-key (plist-get state-keys :visual)) + (insert-key (plist-get state-keys :insert)) + (emacs-key (plist-get state-keys :emacs))) + (cond + ((not (null normal-key)) (evil-define-key 'normal map (kbd normal-key) fn)) + ((not (null visual-key)) (evil-define-key 'visual map (kbd visual-key) fn)) + ((not (null insert-key)) (evil-define-key 'insert map (kbd insert-key) fn)) + ((not (null emacs-key)) (evil-define-key 'emacs map (kbd emacs-key) fn))))) -(defmacro defkey (map keys fn) +(defmacro defkey (map fn &rest keys) "Defines a key binding for FG42 for different types. Defines a keybinding in the given MAP for the given KEYS that maps to the given FN with the given DOCSTRING. - -KEYS should be a plist in the following format: -\(:god :human :evil \"\\)" (let ((god-key (plist-get keys :god)) (human-key (plist-get keys :human)) - (evil-key (plist-get keys :evil))) + (evil-state-key (plist-get keys :evil))) + (when (and (is-evil?) (null evil-state-key)) (error "You should pass :evil keys when you are evil user")) + (when (and (is-god?) (null god-key)) (error "You should pass :god keys when you are a god user")) + (when (and (is-human?) (null human-key)) (error "You should pass :evil keys when you are a human user")) (cond ((is-god?) `(-defkey-god ,map ,god-key ,fn)) ((is-human?) `(-defkey-human ,map ,human-key ,fn)) - ((is-evil? `(-defkey-evil ,map ,evil-key ,fn)))) - (error "Wrong 'race' has been selected, Checkout `fg42-user-race'"))) + ((is-evil?) `(-defkey-evil ,map (quote ,evil-state-key) ,fn))))) (provide 'fg42/key-bindings) ;;; key-bindings.el ends here diff --git a/lib/fg42/utils.el b/lib/fg42/utils.el index f4a4d54..e45fea5 100644 --- a/lib/fg42/utils.el +++ b/lib/fg42/utils.el @@ -7,10 +7,6 @@ (require 'fg42/vars) (require 'fg42/utils/json) -;; Vars ----------------------------------------------------------------------- -(defvar fg42-font "Fira Mono" - "The default font to be used with FG42.") - ;;; Buffer helpers ------------------------------------------------------------ (defun buffer-mode (buffer-or-string) "Return the major mode associated with a the given BUFFER-OR-STRING." diff --git a/lib/fpkg.el b/lib/fpkg.el index 5c4d8c6..866e1d6 100644 --- a/lib/fpkg.el +++ b/lib/fpkg.el @@ -1,7 +1,7 @@ ;;; fpkg --- a simple package manager for FG42 -*- lexical-binding: t; -*- - -;; Copyright (C) 2010-2019 Sameer Rahmani - +;; +;; Copyright (C) 2010-2020 Sameer Rahmani +;; ;; Author: Sameer Rahmani ;; Keywords: lisp fg42 IDE package manager ;; Version: 1.0.0 @@ -36,61 +36,50 @@ (path nil) (source 'elpa)) + +(defvar bootstrap-version nil + "Bootstrap version of straight. This var is used in straight's installer.") + + +(defvar fpkg-packages-path + (expand-file-name ".fpkg/" fg42-home) + "The path to the directory which FPKG will use to store that packages.") + +(defvar fpkg-initilized-p nil + "A boolean flag that indicates whether FPKG is initialized or not.") + (defvar required-packages (make-hash-table) "A hash of `fg42-package structure representing required packages.") ;; Functions ---------------------------------- -(defun all-dependencies-installed? () - "Return t if all the dependencies installed." - (let ((result t)) - (dolist (pkg (hash-table-keys required-packages)) - (when (not (package-installed-p pkg)) - (message "'%s' package is not installed" pkg) - (setq result nil))) - result)) - -(defun install--package (pkg) - "Intall a package via its propreate source." - (let* ((source (fpkg-dependency-source pkg)) - (func-name (concat "install-package-via-" (symbol-name source))) - (install-func - (symbol-function - (intern func-name)))) - (funcall install-func pkg))) - (defun fpkg-initialize () - "Initilize the package.el and related stuff to be used in FG42" - (let ((packages (hash-table-values required-packages))) + "Initilize the straight.e package manager and setup necessary hooks." + (let ((bootstrap-file (concat fpkg-packages-path + "straight/repos/straight.el/bootstrap.el")) + (bootstrap-version 5)) - (require 'package) - - (add-to-list 'package-archives - '("melpa" . "http://melpa.org/packages/") t) - (when (< emacs-major-version 24) - ;; For important compatibility libraries like cl-lib - (add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/"))) - - ;; Initialize package.el - (package-initialize) - - (setq url-http-attempt-keepalives nil) - - (unless (all-dependencies-installed?) - ;; check for new packages (package versions) - (message "%s" "Refreshing package database...") - (package-refresh-contents) - - ;; install the missing packages - (dolist (pkg packages) - (when (not (package-installed-p (fpkg-dependency-name pkg))) - (install--package pkg)))))) + (make-directory fpkg-packages-path t) + (setq straight-base-dir fpkg-packages-path) + (if (not (file-exists-p bootstrap-file)) + (with-current-buffer + (url-retrieve-synchronously + "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" + 'silent 'inhibit-cookies) + (goto-char (point-max)) + (eval-print-last-sexp)) + (load bootstrap-file nil 'nomessage)))) +(defun fpkg-initialize-once () + "Initilize FPKG only once." + (when (not fpkg-initilized-p) + (fpkg-initialize))) + + +(defun depends-on (pkgname) + "Install the given PKGNAME if it isn't installed." + (straight-use-package pkgname)) -(defun depends-on (pkgname &rest args) - "Global function to specify a single dependency" - (let ((pkg (apply 'make-fpkg-dependency :name pkgname args))) - (puthash pkgname pkg required-packages))) -(message "FPKG has been initialized.") (provide 'fpkg) +;;; fpkg.el ends here