Compare commits

..

2 Commits

Author SHA1 Message Date
Mary Salehi 5273c98147 add Header.png in share/images folder 2021-07-16 22:46:14 +01:00
Mary Salehi 52a1f00caf Edit the header image of README.md 2021-07-16 22:26:16 +01:00
268 changed files with 10813 additions and 10190 deletions

22
.gitignore vendored
View File

@ -1,4 +1,3 @@
emacs.dmastodon.plstore
kuso.config.el
kuso.d/*
.build/*
@ -7,7 +6,7 @@ build.log
.cask/*
packages/
lib/magic-buffer.el
/assets/
assets/
./fg42^
/fg42
project-config/
@ -31,13 +30,16 @@ smex-items
elpa/
bm-repository
.fpkg-v3/
website/__pycache__/
website/*.pyc
website/.sass-cache/
website/theme/static/css/bulma.css
website/output/
website/public/
website/*.old.jpg
website/pelican-plugins/
website/.*.swp
website/*~
#*#
*.swp
emacs.d/
/build/
docs/site/orgs/cubes/
**/*/sitemap.inc
result
v4/
emacs.d/

View File

@ -0,0 +1,16 @@
## Summary
<Describe your changes here including your rational, the problem, your solution vice versa>
### QA
<Describe the steps necessary to test your changes>
### Checklist
[ ] Is the linter happy?
[ ] Is the byte compiler happy (no warning) ?
[ ] Is it backward compatible
[ ] Did you document your changes ?
[ ] Did you update the CHANGELOG ?
[ ] Did you actually test your changes ?

1
CNAME Normal file
View File

@ -0,0 +1 @@
fg42.lxsameer.com

148
CONTRIBUTE Normal file
View File

@ -0,0 +1,148 @@
# Contribution Guidelines
*FG42* is a free software and a community of Emacs developers who like to share
their ideas and tools. We encourage you to join us. The community is what matters
to us. Here is a brief overview of contribution guidelines, which we ask all
contributors to follow.
## Asking for help
If you want to ask an usage question, first make sure to read the `README.md` file
and the documents of *FG42*. If you still need help feel free to join us via
[out gitter channel](https://gitter.im/FG42/FG42).
## Reporting issues
Issues have to be reported on our [issues tracker](https://gitlab.com/FG42/FG42/issues). Please:
- Check that the issue has not already been reported.
- This can be achieved by searching keywords on the [issues tracker](https://gitlab.com/FG42/FG42/issues).
- Try to use a clear title, and describe your problem with complete sentences.
- Include your emacs version and `~/.fg42.el` file as well.
- If possible, try to include details on how to reproduce it, like a step by
step guide.
## Contributing code
Code contributions are welcome. Please read the following sections carefully. In
any case, feel free to join us on [out gitter channel](https://gitter.im/FG42/FG42) to ask questions about
contributing!
### General contribution
#### License
The license is *GPLv2* for all parts specific to *FG42*, this includes:
- The initialization and core files
- All the built-in extensions.
For files not belonging to FG42 like local packages and libraries, refer
to the header file. Those files should not have an empty header, we may not
accept code without a proper header file.
#### Conventions
We follow these simple rules:
* Make elisp linter happy
* Make byte compiler happy `make compile`
* Follow functional patterns and avoid huge functions
* Seperate each root level expression by two new lines (e.g function definitions)
* Put `(comment ...)` expression after each macro/function to demonstrate the usage.
* Write good docstrings
* Choose meaningful names
* Follow the indentation guides made in FG42
* Prefix the functions with a prefix to differentiate them from other functions.
for example `fg42-namespace/functoin-name`.
* use `<prefix>/-<fn-name>` for private/internal function names
* use `/` to categorize functions into namespaces (air quote)
#### Pull-Request
Submit your contribution against the `master` branch. The `stable` branch
is going to be our last stable version only.
Please make one PR per feature. Keep your PRs as small as possible so we can review them
easily. Don't forget to make the byte compiler and the linter happy. There should not
be any build error or warning on `make compile`. We like how [Linus Torvalds thinks
about build warnings](https://linuxreviews.org/Linus_Torvalds#On_Build-Testing).
Write commit messages according to adapted [this article](https://chris.beams.io/posts/git-commit/):
- Include the extension or library name in the title inside square brackets
- Use present tense and write in the imperative: “Fix bug”, not “fixed bug” or
“fixes bug”.
- Start with a capitalized, short (72 characters or less) summary, followed by a
blank line.
- If necessary, add one or more paragraphs with details, wrapped at 72
characters.
- Separate paragraphs by blank lines.
This is a model commit message:
```
[FPKG] Capitalized, short (72 chars or less) summary
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body. The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.
Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug." This convention matches up with commit messages generated
by commands like git merge and git revert.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, followed by a
single space, with blank lines in between, but conventions vary here
- Use a hanging indent
```
[[https://github.com/magit/magit/][Git Commit]] and [[https://github.com/magit/magit/][Magit]] provide Emacs mode
for Git commit messages, which helps you to comply to these guidelines.
### Contributing an extension
Technical aspects TBD
Each file should be GPL compliant and contain the following header:
```lisp
;;; FILENAME --- SHORT DESCRIPTION
;;
;; Copyright (c) 2010-2020 Sameer Rahmani & Contributors
;;
;; Author: YOUR FULL NAME <YOUR EMAIL>
;; URL: https://gitlab.com/FG42/FG42
;; Version: VERSION
;;
;; 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:
;; THE COMMENTARY ON THE MOST IMPORTANT ASPECT OF THE EXTENSION
;;
;;; Code:
```
You should replace `FILENAME` by the name of the file (e.g. `packages.el`).
Don't forget to replace `YOUR FULL NAME` and `YOUR EMAIL` also.
#### Contribute to an existing extension
If you are contributing to an already existing extension, you should not modify any
header file.
* Credits
This `CONTRIBUTING` file is partially based on the [Rails Contribution
guidelines](https://github.com/rails/rails/blob/master/CONTRIBUTING.md)
and [Flycheck Contribution guidelines](https://github.com/flycheck/flycheck/blob/master/CONTRIBUTING.md)
and [Spacemacs Contribution guidelines](https://raw.githubusercontent.com/syl20bnr/spacemacs/master/CONTRIBUTING.org).

71
Makefile Normal file
View File

@ -0,0 +1,71 @@
.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
@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
@cp ./scripts/fg42-wm ./fg42-wm
@echo "export FG42_HOME=$(shell pwd)" >> ./fg42
@echo "export FG42_HOME=$(shell pwd)" >> ./fg42-wm
@echo 'FG42_WM=false emacs --name FG42 --no-site-file --no-site-lisp --no-splash --title FG42 -l $$FG42_HOME/fg42-config.el "$$@"' >> ./fg42
@echo 'FG42_WM=true emacs --name FG42 --no-site-file --no-site-lisp --no-splash --title FG42 -l $$FG42_HOME/fg42-config.el "$$@"' >> ./fg42-wm
@chmod +x ./fg42
@chmod +x ./fg42-wm
@sudo mkdir -p /usr/local/bin/
@sudo rm -f /usr/local/bin/fg42
@sudo rm -f /usr/local/bin/fg42-wm
@sudo ln -s `pwd`/fg42 /usr/local/bin/fg42
@sudo ln -s `pwd`/fg42-wm /usr/local/bin/fg42-wm
@echo "Copying share files..."
@sudo mkdir -p /usr/share/fg42/
@sudo cp ./share/applications/fg42.desktop /usr/local/share/applications
@sudo cp -r ./share/icons/hicolor/ /usr/local/share/icons
@sudo cp -r ./share/* /usr/share/fg42/
@sudo cp -r ./share/xsessions/fg42.desktop /usr/share/xsessions/
@echo " "
@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/
.PHONY: compile
compile:
@$(PWD)/fg42-new --script scripts/compiler.el
.PHONY: clean
clean:
@rm -rf $(shell find `pwd` -iname "*~")
@rm -rf $(shell find `pwd`/core -iname "*.elc")
.PHYNY: dummy-x
dummy-x:
Xephyr -br -ac -noreset -screen 800x600 :1
.PHONY: test-wm
test-wm:
DISPLAY=:1 FG42_WM=true FG42_V3=true fg42-wm

223
README.md Executable file
View File

@ -0,0 +1,223 @@
<div align="center"><img src="https://devheroes.codes/FG42/FG42/raw/branch/master/share/images/Header.png" alt="FG42" align="center" /></div>
<a href="https://gitter.im/FG42/FG42?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge"><img src="https://badges.gitter.im/FG42/FG42.svg" /></a>
<br/><br/>
# Future Gadgets 42
If you love **GNU/Emacs**, If you love to program in an editor instead of big slow IDE but still enjoy to
have a handy code editor then **FG42** is the right choice for you.
If you need help, or even want to just say hello, try our **IRC** channel on freenode: **#5hit**.
## Download
* [Latest Stable - 2.31.3](https://gitlab.com/FG42/FG42/-/jobs/artifacts/2.31.3/raw/fg42.2.31.3.tar.gz?job=build-package)
* [Latest Master](https://gitlab.com/FG42/FG42/-/jobs/artifacts/master/raw/fg42.master.tar.gz?job=build-branches)
## Dependencies
In order to run **FG42** you need **GNU Emacs >= 25**. FG42 uses several extensions internally
which each of the has different external dependencies. To gain more information about external
dependencies ( If we failed to tell you inside the **FG42** ) just run the `describe-extension`
command.
## Install a pre built package
Download one of the prebuilt packages and follow these instructions:
```bash
# extract the content of the tarball in your home directory
$ tar zxvf <downloaded package>.tar.gz -C ~/
# You can clone it where ever your want
$ cd ~/.fg42/
$ make install
# Run fg42, It will download and build some lisp dependencies on the first execution.
$ fg42
```
## Install from source
In order to install **FG42**, issue the following commands:
```bash
# clonse the FG42 repository in ~/.fg42 directory
$ git clone https://gitlab.com/FG42/FG42.git ~/.fg42/
# You can clone it where ever your want
$ cd ~/.fg42/
$ make install
# Run fg42, It will download and build some lisp dependencies on the first execution.
$ fg42
```
Since the installer script uses `sudo`, during the installation process,
you'll have to enter your password. Make sure that you're user account has
a `sudo` access.
If you suffer from poor internet connection (like people in my homeland),
you can also download the tarball from release section and extract the tarball
in your `$HOME` directory. So you're going to end up with `.fg42` directory in
your `$HOME` and all you have to do is to install it using `make install` command.
**NOTE**: Please note that the tarball releases are still experimental and might have
some issues since they contain the elisp packages as well. In case of any problem
please report the issue.
Enjoy using **FG42** ;)
## Configuration
After installation there would be a file at `~/.fg42.el` which is the user specific
configuration of **FG42**. You can configure your copy of **FG42** using this file.
Also you can generally use this file to configure Emacs as well.
## Terms & Concepts
FG42 introduced some new features to the Vanilla Gnu/Emacs. So you migh encounter several of these features during your
journey. It's a good idea to at least know what you're dealing with.
### Extensions
FG42 created around the idea of extensions. Each extension extends the FG42 functionality for a certain language or use case.
For example `clojure` extension adds support for a integrated development environment for `clojure` language. All the configuration
related to this environment leave inside that extension. By default, all the extensions which ships with FG42 are enabled. In order
to disable any extension which you might not need, just comment them out in your user configuration file in `~/.fg42.el`. For example
here is my own list:
```lisp
(activate-extensions 'editor
'development
'web
'editor-theme
'javascript
;;'ruby
'clojure
;;'php
'python)
;;'arduino
```
In order to learn more about each extension you can use `M-x describe-extension`.
### Abilities
Abilities are the smallest piece of configuration which add support for a certain functionality to **FG42**. Each extension contains several abilities.
Using abilities you can choose the set of abilities you like and disable those which you don't like. For example `helm` and `ido` are two different
library which conflicts with each other by we have an ability for each of them in the system, so you can choose which one to use and disable the other one.
In order to disable any ability, just add them to your configuration file in `~/.fg42.el`. For example my current disabled abilities are:
```lisp
(disable 'rbenv-global 'helm 'spell 'linum 'ivy 'smart-mode-line 'desktop-mode)
```
In the above list I disabled `helm` because I want to use `ido`. At the moment there is no way to find out about all the enabled abilities at runtime. Or
discover what abilities present in any extension (You can take a look at extension docs using `describe-extension` command) at runtime. But I'll add something
later :P.
## Documentation
If you're familiar with **GNU/Emacs** you're not going to have a problem with getting
help. But just to clrearify here is a list of keybindings that may guide you during
your experience:
| Key bindings | command | Description |
|:------------:|--------:|------------------|
| `C-?` | cheatsheet-show | Quick cheatsheet |
| | describe-extension | It's going to ask you an extension name and show you the documentation of that extension |
| `C-h m` | describe-mode | All the information and keybindings of your current modes. e.g open of a `ruby` file and use the this keybinding to take a look at all the keybinding of ruby extension |
## How to implement your own extension:
In this part we will explore the extensibility features of the FG42. As an example
we will add LaTeX autocompletion and other useful features to our emacs based on AUCTeX
and company-auctex [company-auctex](https://github.com/alexeyr/company-auctex).
We can install the required package manually by ``` install M-x package-install RET company-auctex RET ``` or the FG42
would do this for us based on its configurations.
Assume that our extension is called latex, to this end we are needed to create a file and a directory in the following
directories:
```bash
yourfg42home/lib/extensions/latex.el
yourfg42home/lib/extensions/latex/init.el
```
First we are going to explore the latex.el. your file needs to include these parts:
```lisp
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/latex/init)
```
extensions/latex/init says to FG42 that the corresponding init file is in the latex directory and in the init.el file.
after that, you must add the MELPA dependencies you wish to install and use, in our case:
```lisp
(depends-on 'company-auctex)
```
There are other doc and extension functions you may like to implement for your versioning and documentation stuff.
finally you have to provide your extension using:
```lisp
(provide 'extensions/latex)
```
At this point our latex.el is done and we have to implement the init.el file. extension customization, key-binding, and hooks on the
major modes, etc. are configured in init.el. The only protocol you have to recall is that name of your init function should
follow this pattern: lisp extensions/latex-initialize() and you have to provide it at the end.
for example:
```lisp
(defun extensions/latex-initialize ()
;LaTeX development initialization
(require 'company-auctex)
(add-hook 'latex-mode #'company-auctex-init))
(provide 'extensions/latex/init)
```
FG42 will add your package to its classpath and would load it on the related major mode.
Finally you have to enable this extension in the yourfg42home/fg42-confilg.el file.
```lisp
(activate-extensions 'latex etc)
```
you are done. enjoy using your extension!
## Latex-lsp mode
FG42 has a builtin support for LaTeX language. In the latest version Microsoft lsp-latex language server has been used for this purpose. You need to download the [texlab](https://github.com/latex-lsp/texlab/releases) binary for your operating system and put it in your class path (e.g /usr/bin/texlab). If FG42 didn't load the server automatically, you can run the server with the following command:
```
M-x latex-run-lsp
```
## Debugging
If you ran into an issue and want to debug FG42, the best and easiest way is to turn on
debugging by uncommenting `(setq debug-on-error t)` in your configuration (`~/.fg42.el`)
and restarting FG42. After that you'll get a traceback for any exception in FG42.
## what's with the name?
I'm a huge fan of [Steins Gate](https://en.wikipedia.org/wiki/Steins;Gate) anime and I follow its
naming convensions on **Future Gadgets 42**.
## Why we moved from Github ?
We're not happy with Microsoft buying Github and we don't trust a company like Microsoft because of their history and
their strategies (For more information take a look at ([Halloween documents](https://en.wikipedia.org/wiki/Halloween_documents)).
So we decided to move to Gitlab as an alternative and we are happy here so far.
# License
FG42 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 2 of the License, or
any later version.
FG42 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
All the documents of FG42 that locate in 'doc' directories release
under the term of GNU FDL.
Copyright (C) 2010-2018 Sameer Rahmani <lxsameer@gnu.org>

View File

@ -1,108 +0,0 @@
* Future Gadgets 42
*FG42* is an Emacs based editor that utilizes [[https://nixos.org/][Nix]], and shipped preconfigured. While it
is the Emacs that you love :heart:, it breaks the tradition by not using any of Emace's
package managers (More on that later). It provides a self-contained program and
contains all the runtime dependencies including Emacs itself.
** Requirements
The only requirement to install *FG42*, is [[https://nixos.org/][Nix]]. If you don't use Nix, try it today.
It's amazing.
** Installation
If you're using Nix (and not NixOS), then you can install *FG42* like:
#+BEGIN_SRC bash
# Install emacs, make and texinfo
$ nix profile install "git+https://devheroes.codes/FG42/FG42#"
# Or via nix build like:
nix build "git+https://devheroes.codes/FG42/FG42#"
#+END_SRC
If you're using NixOS or HomeManager you can use *FG42* as an input
to your flake. If your not using flakes, I'm pretty sure you know
what you are doing so I leave it to your experience.
#+BEGIN_SRC nix
{
description = "Exmaple flake";
inputs = {
fg42.url = "git+https://devheroes.codes/FG42/FG42";
};
outputs = { self, fg42, ... } @ inputs:
let
# I just use linux and currently only x86_64
system = "x86_64-linux";
# Grab the default package of FG42
fg42 = fg42.outputs.packages.${system}.default;
in {
# Now you can use the 'fg42' package in your package list
....
};
}
#+END_SRC
** Configuration
FG42 comes pre-configured, but if you need to add your own configuration you can
do it in =~/.fg42.el=.
** Flags
TBD
** Debugging
Debugging is *OFF* by default in *FG42*. You can turn it on by setting the ~FG42_DEBUG~
environment variable to ~1~.
** FAQ
*** Why Nix? Have you tried Emacsian package manager?
Yes we tried many of them. We started by a manual solution that the name ~fpkg~ remains
as remembrance of that effort. We moved to [[https://github.com/dimitri/el-get][el-get]], then [[https://github.com/cask/cask][Cask]], [[https://github.com/emacs-eldev/eldev][ElDev]] and finally we
landed on [[https://github.com/radian-software/straight.el][straight.el]] on ~V3~. But none of the provided the stability that we need.
But on ~V4~ (Current version), We've change the approach by disabling all the package managers
(don't worry you can still use them if you want to) and used *Nix* to manage everything. Both
elisp dependencies and system dependencies. This way we get reproducible builds that gives
us stability and reliability. Also we get to pin every single dependency version even Emacs
itself. So no more ":shrug: But it works on my computer".
*** what's with the name?
I'm a huge fan of [Steins Gate](https://en.wikipedia.org/wiki/Steins;Gate) anime and I follow its
naming convensions on *Future Gadgets 42*.
*** Why we moved from Github ?
We're not happy with Microsoft buying Github and we don't trust a company like Microsoft because of their history and
their strategies (For more information take a look at [[https://en.wikipedia.org/wiki/Halloween_documents][Halloween documents]].
So we decided to move to Devheroes as an alternative and we are happy here so far.
* Contribute
FG42 made possible by the effort of the community of [[docs/site/pages/contributors.org][Contributors]].
If you're interested in *FG42* and wants to contribute to the project please follow
the [[docs/site/pages/how-to-contribute.org][How to Contribute Guitd]]. Also please read our [[docs/site/pages/code-of-conduct.org][Code of Conduct]] as well.
* License
FG42 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 2 of the License, or
any later version.
FG42 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
All the documents of FG42 that locate in 'doc' directories release
under the term of GNU FDL.
Copyright (C) 2010-2024 Sameer Rahmani <lxsameer@gnu.org>

137
bin/fbt Executable file
View File

@ -0,0 +1,137 @@
:;exec emacs --no-site-file --no-site-lisp -batch -l "$0" -f main "$(cd "$(dirname "$0")/.." >/dev/null 2>&1 ; pwd -P)" "$@"
;;; FGBuildTool --- The build tool for FG42
;;
;; Copyright (c) 2010-2020 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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:
;; FG42 Build Tool for FBT for short is a tool on top of Emacs to build
;; FG42. To learn how to use it run it via a shell.
;;
;;; Code:
(defvar FG42-VERSION "3.0.0-snapshot"
"The version number of the current build of FG42.")
(defconst fbt-usage "
Usage:
fbt [PARAMS] COMMAND [...]
COMMANDS:
compile [DIR] - Compiles the given DIR to bytecodes (default: \"core\").
build - Builds FG42 by compiling the code and installing dependencies.
clean [DIRS] - Clean up the given list of directories (default: \"code\" \"fbt\").
fpkg [...] - The CLI insterface to FPKG (FG42 Package manager)
lint [DIR] - Run the ELisp linter on the files on the given DIR.
PARAMS:
:d - Turns on the debug mode.
:e expr - Run the given `expr' before any operation.
By default FBT loads the `system.el' file from the root path of `FG42' and looks
for a system with the name `FG42' to use it as the source for the build operations.
You can change this behaviour by running following command:
$ fbt :e '(setq fg42-system 'SOMESYSTEM fg42-system-path \"path/to/a/elisp/file.el\"))' COMMAND...
This way FBT will load an elisp file at \"path/to/a/elisp/file.el\" and looks for a system
called `SOMESYSTEM' in it as the source system for the build operations.
")
(defun read-args (args)
"Parse the given ARGS and return a list of params and args.
The only parameter at the moment is `-e' which basically gets a string
of elisp and eval it before the commant. The return value is a list
which the first element is the string to evaluate and the second one
is the rest of the arguments."
(if (member ":d" args)
(setq debug-on-error t)
(delete ":d" args))
(if (string= (car args) ":e")
(list (cadr args) (cddr args))
(list nil args)))
(defun todo (dir)
"Extract the TODO tags from the comments in the given DIR."
(message "TBD"))
(defun print-help (command)
"Print out a usage instructions and print out the invalid msg for COMMAND."
(when command
(warn "I don't know about '%s' command.\n" command))
(message fbt-usage))
(defun main ()
"Execute a subcommand by looking into input arguments of the script."
(message (version))
(message "\nFG42 Build tool v%s\n\n" FG42-VERSION)
(let* ((fg42-home (car command-line-args-left))
(parsed-args (read-args (cdr command-line-args-left)))
(eval-string (car parsed-args))
(command (caadr parsed-args))
(args (cdadr parsed-args)))
;; FG42 Needs this env var to know where had it been installed
(setenv "FG42_HOME" fg42-home)
(setenv "FG42_VERSION" FG42-VERSION)
(defvar fg42-system-path (concat (file-name-as-directory fg42-home) "system"))
(defvar fg42-system 'FG42)
(add-to-list 'load-path (concat (file-name-as-directory fg42-home) "core"))
(add-to-list 'load-path (concat (file-name-as-directory fg42-home) "fbt"))
;; Load the default system without user configurations
(when eval-string
(eval (car (read-from-string eval-string))))
(load fg42-system-path)
(require 'fbt/utils)
(require 'fbt/compile)
(require 'fbt/lint)
(require 'fbt/fpkg)
(require 'fbt/build)
(let ((system (symbol-value fg42-system)))
;; Add the fpkg path to the load path. For the sake of `straight.el'.
;; This way installed packages will be accessable for build tools as well.
(fpt-fpkg/initialize-load-path system)
(cond
((string= command "fpkg") (funcall #'fbt-fpkg system args))
((string= command "lint") (funcall #'lint (or (car args) "core")))
((string= command "compile") (funcall #'fbt-compile/compile (or (car args) "core")))
((string= command "clean") (funcall #'fbt-build/clean (or args '("core" "fbt"))))
((string= command "build") (funcall #'fbt-build/build args))
(t (print-help command))))))
;; Local Variables:
;; mode: emacs-lisp
;; End:
;;; fbt ends here

10
bin/fg42-new Executable file
View File

@ -0,0 +1,10 @@
#! /bin/sh
export FG42_HOME="$(cd "$(dirname "$0")/.." >/dev/null 2>&1 ; pwd -P)"
FG42_WM=false emacs --name FG42 \
--no-site-file --no-site-lisp --no-splash --title FG42 \
-L $FG42_HOME/core \
-L $FG42_HOME/extensions \
-l $FG42_HOME/core/fg42.el \
-l ~/.v3.el "$@"

64
build.el Normal file
View File

@ -0,0 +1,64 @@
;;; build --- build script for FG42
;;
;; Copyright (C) 2010-2021 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:
;;; Code:
(setq debug-on-error t)
(setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3")
(setq user-emacs-directory (concat (getenv "HOME") "/.fg42/"))
(add-to-list 'load-path (concat (getenv "HOME") "/.fg42/lib"))
(require 'fg42)
(require 'fpkg)
(setq fg42-home (concat (getenv "HOME") "/.fg42/"))
(setq fg42-tmp (concat fg42-home "/tmp"))
(theme themes/color-theme-doom-one)
(i-am-god)
(disable 'rbenv 'helm 'spell 'linum 'tabbar
'smart-mode-line 'desktop-mode 'jedi
'dired+ 'guru 'emoji 'elpy 'github
'versioned-backup)
(activate-extensions 'editor
'development
'web
'editor-theme
'javascript
'ruby
'clojure
'haskell
'php
'common-lisp
'python
'serene
'typescript
'arduino
'java
'racket
'irc
'latex)
(fg42-initialize)
(provide 'build)
;;; build.el ends here

113
config/fg42.user.el Normal file
View File

@ -0,0 +1,113 @@
;; Uncomment this for debugging purposes
;;(setq debug-on-error t)
;; THEME
;; =====
;; Load the default theme
;; Other options are:
;; (theme themes/color-theme-spacemacs-light)
;; (theme themes/color-theme-spacemacs-dark)
;; (theme themes/color-theme-doom-dracula)
(theme themes/color-theme-doom-one)
;; (theme themes/color-theme-doom-molokai)
;; ABILITIES
;; =========
;; Disable abilities which you don't want.
(disable 'rbenv 'helm 'spell 'linum 'tabbar 'ido 'ivy
'smart-mode-line 'desktop-mode 'jedi
'dired+ 'guru 'emoji 'elpy 'github
'versioned-backup)
;; EXTENSIONS
;; ==========
;; Uncomment extensions that you may need.
(activate-extensions 'editor
'development
'web
'editor-theme
'javascript
'typescript
'ruby
'clojure
'haskell
'php
'go
'common-lisp
'python
'arduino
'java
'racket
'devops
'irc
'latex)
;; What are you ?
(i-am-god)
;; i-am-god => Emacs user.
;; i-am-human => A user of other boring editors.
;; i-am-evil => An evil user. A vim user.
;; Example of things you can do in your ~/.fg42.el config file:
;;
;; Setting your TODO file path:
;; (setq fg42-todo-file "~/.TODO.org")
;; or you can open a remote TODO file
;; (add-hook 'fg42-before-open-todo-hook 'disable-projectile)
;; (setq fg42-todo-file "/ssh:user@host:/home/USER/.TODO.org")
;;
;; Set some environment variables for your fg42 to use
;; (setenv "http_proxy" "localhost:8118")
;; (setenv "https_proxy" "localhost:8118")
;;
;; Alwasy open a your TODO file as your first buffer
;; (add-hook 'fg42-after-initialize-hook 'fg42-open-todo)
;; If you're using tools like rbenv or nodenv or other similar tools
;; to manage versions of your favorite language, then you need to
;; add their shims to your path. Follow the example below:
;;
;; (setenv "PATH" (concat "/home/USER/.rbenv/shims:"
;; "/home/USER/.nodenv/shims:"
;; "/home/USER/bin:" (getenv "PATH")))
;;
;; Ofcourse you need to change the USER to your username
;; If you have a separate bin directory as well you can add it
;; to the exec-path as follows:
;;
;; (add-to-list 'exec-path "/home/USER/bin")
;;
;; abilities like clojure which uses the lien tools need to find
;; specific tools (lein in this case) in your exec-path.
;; IRC Extension configuration ------------------------------------------------
;; Setup all the servers and channels you need
;; (setq irc-servers
;; '(("irc.freenode.net"
;; :port 6697
;; :encryption tls
;; :channels ("#5hit" "#emacs"))))
;; Set you nickname
;; (setq irc-nickname "awesome-fg42-user")
;; You can use password manager for storing you IRC credentials.
;; NOTE: you need to have a pair of GPG keys for this.
;;
;; Add the following to your ~/.authinfo.gpg :
;;
;; machine freenode login <username> port nickserv password <password>
;;
;; Or if you don't want to use the password manager your can directly
;; set it up like this:
;; (setq irc-auth '(("freenode" nickserv "some_user" "p455w0rd")
;; ("freenode" chanserv "some_user" "#channel" "passwd99"))
;;
;;
;; If you want to change the default font uncomment the following line
;;(setq fg42-font "Terminus")

View File

@ -1,10 +1,10 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani & Contributors
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://devheroes.codes/FG42/FG42
;; Version: 4.0.0
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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
@ -21,16 +21,18 @@
;;
;;; Commentary:
;;; Code:
(eval-when-compile
(require 'fpkg))
(setq debug-on-error t)
(require 'fg42/cube)
(require 'cubes/elisp)
(require 'cubes/org)
(defsystem default-system ()
(fg42/elisp-cube)
(fg42/org-cube))
(use! elfeed
"The best rss reader you can ask for."
:commands elfeed
:bind
("C-x w" . elfeed))
(fg42/start! (default-system))
(provide 'fg42/rss)
;;; rss.el ends here
(provide '.fg42)
;;; .fg42.v3.el ends here

104
core/cubes/editor.el Normal file
View File

@ -0,0 +1,104 @@
;;; ElispCube --- The elisp cube for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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 'fpkg)
(require 'fg42/cube)
(defflag font-icons
"Enable the support for font icones in FG42.")
(defcube fg42/buffer-navigation-cube
(:docs "cubes/fg42/buffer-navigation-cube.org")
(fpkg/use avy
:bind ("M-1" . avy-goto-word-1)))
(defcube fg42/window-navigation-cube
(:docs "cubes/fg42/window-navigation-cube.org")
(fpkg/use ace-window
:bind ("C-<tab>" . ace-window)))
(defcube fg42/font-cube
(:docs "cubes/fg42/font-cube.org")
(let ((font (or (plist-get fg42/font-cube-params :font-name)
"Fira Mono"))
(size (or (plist-get fg42/font-cube-params :font-size)
12)))
;; Sets the default font to fg42 font
(add-to-list 'default-frame-alist
(cons 'font (format "%s-%d" font size)))
(set-face-attribute 'default t :font font)))
(defcube fg42/editor-cube
(:docs "cubes/fg42/editor-cube.org")
(fpkg/use rainbow-delimiters
;; It doesn't work due to a problem/conflict in rainbow-delimiters
;; But we use it any way they might fix it
:hook (prog-mode . rainbow-delimiters-mode))
(when-flag font-icon
(fpkg/use all-the-icons))
;; 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.
;; 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)
;; Global configurations
(tool-bar-mode -1)
(scroll-bar-mode -1)
(menu-bar-mode -1)
(column-number-mode t)
(show-paren-mode t)
(defalias 'yes-or-no-p 'y-or-n-p)
;; Hooks ---
;; 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))
(provide 'cubes/editor)
;;; editor.el ends here

View File

@ -1,10 +1,10 @@
;;; ElispCube --- The elisp cube for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani & Contributors
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://devheroes.codes/FG42/FG42
;; Version: 4.0.0
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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
@ -22,17 +22,22 @@
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/cube)
(defun fg42/setup-elisp ()
"Setup the Emacs Lisp development environment."
(use! eros
:init
(require 'eros)
(eros-mode))
(defcube fg42/elisp-cube
(:docs "cubes/fg42/elisp-cube.org")
(fpkg/use rainbow-delimiters
;; It doesn't work due to a problem/conflict in rainbow-delimiters
;; But we use it any way they might fix it
:hook (prog-mode . rainbow-delimiters-mode))
(fpkg/use paredit
:hook (emacs-lisp-mode . paredit-mode))
(add-hook 'emacs-lisp-mode-hook #'rainbow-delimiters-mode))
(provide 'fg42/cubes/elisp)
(provide 'cubes/elisp)
;;; elisp.el ends here

40
core/cubes/elisp/core.el Normal file
View File

@ -0,0 +1,40 @@
;;; ElispCube --- The elisp cube for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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:
;; Cubes are the building blocks of any `FG42' editor. Each `cube' is a
;; unit which defines different abilities in a deterministic and idempotent
;; way. Cubes are composable and a composition of cubes creates an editor.
;;
;;; Code:
(defun fg42/elisp-hook-handler ()
"Configure the elisp mode."
(require 'rainbow-delimiters)
(require 'paredit)
(rainbow-delimiters-mode t)
(paredit-mode t)
(message "Elisp cube is done"))
(provide 'cubes/elisp/core)
;;; core.el ends here

37
core/cubes/org.el Normal file
View File

@ -0,0 +1,37 @@
;;; OrgCube --- The elisp cube for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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:
;; Cubes are the building blocks of any `FG42' editor. Each `cube' is a
;; unit which defines different abilities in a deterministic and idempotent
;; way. Cubes are composable and a composition of cubes creates an editor.
;;
;;; Code:
(require 'fg42/cube)
(defcube fg42/org-cube ()
;;:hooks '((org-mode-hook . iii))
;:init #'iii
:dependencies '((:name org :version :latest)))
(provide 'cubes/org)
;;; org.el ends here

View File

@ -1,10 +1,10 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;; RegionExpansionCube --- The elisp cube for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani & Contributors
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://devheroes.codes/FG42/FG42
;; Version: 4.0.0
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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
@ -21,19 +21,15 @@
;;
;;; Commentary:
;;; Code:
(eval-when-compile
(require 'fpkg))
(require 'fpkg)
(require 'fg42/cube)
;; 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))))
(defcube fg42/region-expansion-cube
(:docs "cubes/fg42/region-expansion.org")
(fpkg/use expand-region
:bind ("C-=" . er/expand-region)))
(provide 'fg42/eglot)
;;; eglot.el ends here
(provide 'cubes/region-expansion)
;;; region-expansion.el ends here

54
core/cubes/wm.el Normal file
View File

@ -0,0 +1,54 @@
;;; WMCube --- The elisp cube for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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 'fpkg)
(require 'fg42/flags)
(require 'fg42/cube)
(require 'fg42/utils)
(autoload-cube 'fg42/initialize-wm "wm/core.el" "Initalize the WM mode.")
(defflag wm
"The flag to enable WM mode in FG42.")
(defmacro when-wm (&rest body)
"Run the BODY only if in wm mode."
(if (string= (getenv "FG42_WM") "true")
`(progn ,@body)
nil))
(defcube fg42/wm-cube
(:docs "cubes/fg42/wm-cube.org")
(if-flag wm
(when-wm
(message "[WM] Initilizing...")
(fpkg/use exwm)
(fg42/initialize-wm))
(error "[SKIP] WM flag is not active.")))
(provide 'cubes/wm)
;;; wm.el ends here

159
core/cubes/wm/core.el Normal file
View File

@ -0,0 +1,159 @@
;;; WMCube --- The elisp cube for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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:
(defun wm-randr ()
"RandR support for WM"
(when-wm
(require 'exwm-randr)
(setq exwm-randr-workspace-output-plist '(0 "HDMI-1"
1 "HDMI-1"
2 "HDMI-1"
3 "HDMI-1"
4 "HDMI-1"
5 "HDMI-1"
6 "eDP-1"
7 "HDMI-1"
8 "HDMI-1"
9 "HDMI-1"))
(add-hook 'exwm-randr-screen-change-hook
(lambda ()
(start-process-shell-command
"xrandr" nil "xrandr --output HDMI-1 --above eDP-1 --mode 1920x1080")))
(exwm-randr-enable)))
(defun fg42/initialize-wm ()
"Initilize EXWM window manager with the given PARAMS."
(interactive)
(require 'exwm)
(require 'exwm-config)
(require 'exwm-systemtray)
(exwm-config-ido)
;; Set the initial number of workspaces (they can also be created later).
(setq exwm-workspace-number 10)
;; All buffers created in EXWM mode are named "*EXWM*". You may want to
;; change it in `exwm-update-class-hook' and `exwm-update-title-hook', which
;; are run when a new X window class name or title is available. Here's
;; some advice on this topic:
;; + Always use `exwm-workspace-rename-buffer` to avoid naming conflict.
;; + For applications with multiple windows (e.g. GIMP), the class names of
;; all windows are probably the same. Using window titles for them makes
;; more sense.
;; In the following example, we use class names for all windows except for
;; Java applications and GIMP.
(add-hook 'exwm-update-class-hook
(lambda ()
(unless (or (string-prefix-p "sun-awt-X11-" exwm-instance-name)
(string= "gimp" exwm-instance-name))
(exwm-workspace-rename-buffer exwm-class-name))))
(add-hook 'exwm-update-title-hook
(lambda ()
(when (or (not exwm-instance-name)
(string-prefix-p "sun-awt-X11-" exwm-instance-name)
(string= "gimp" exwm-instance-name))
(exwm-workspace-rename-buffer exwm-title))))
;; Global keybindings can be defined with `exwm-input-global-keys'.
;; Here are a few examples:
(setq exwm-input-global-keys
`(
;; Bind "s-r" to exit char-mode and fullscreen mode.
([?\s-r] . exwm-reset)
([?\s-g] . keyboard-quit)
([8388640] . other-window)
;; Bind "s-w" to switch workspace interactively.
([?\s-w] . exwm-workspace-switch)
;; Bind "s-0" to "s-9" to switch to a workspace by its index.
,@(mapcar (lambda (i)
`(,(kbd (format "s-%d" i)) .
(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
(number-sequence 0 9))
;; Bind "s-&" to launch applications ('M-&' also works if the output
;; buffer does not bother you).
([?\s-d] . (lambda (command)
(interactive (list (read-shell-command "$ ")))
(start-process-shell-command command nil command)))
;; Bind "s-<f2>" to "slock", a simple X display locker.
([s-f2] . (lambda ()
(interactive)
(start-process "" nil "/usr/bin/slock")))))
;; To add a key binding only available in line-mode, simply define it in
;; `exwm-mode-map'. The following example shortens 'C-c q' to 'C-q'.
(define-key exwm-mode-map [?\C-q] #'exwm-input-send-next-key)
(push ?\C-c exwm-input-prefix-keys)
;; The following example demonstrates how to use simulation keys to mimic
;; the behavior of Emacs. The value of `exwm-input-simulation-keys` is a
;; list of cons cells (SRC . DEST), where SRC is the key sequence you press
;; and DEST is what EXWM actually sends to application. Note that both SRC
;; and DEST should be key sequences (vector or string).
(setq exwm-input-simulation-keys
`(
;; movement
(,(kbd "C-b") . left)
(,(kbd "M-b") . ,(kbd "C-<left>"))
(,(kbd "C-f") . right)
(,(kbd "M-f") . ,(kbd "C-<right>"))
(,(kbd "C-p") . up)
(,(kbd "C-n") . down)
(,(kbd "C-a") . home)
(,(kbd "C-e") . end)
(,(kbd "M-v") . prior)
(,(kbd "C-v") . next)
(,(kbd "C-d") . delete)
;;(,(kbs "C-k") . [S-end delete])
;; navigation
(,(kbd "C-c b") . ,(kbd "M-<left>"))
(,(kbd "C-c f") . ,(kbd "M-<right>"))
(,(kbd "C-c w") . ,(kbd "C-w"))
(,(kbd "C-w") . ,(kbd "C-x"))
(,(kbd "M-w") . ,(kbd "C-c"))
(,(kbd "C-y") . ,(kbd "C-v"))
;; search
(,(kbd "C-s") . ,(kbd "C-f"))))
;; You can hide the minibuffer and echo area when they're not used, by
;; uncommenting the following line.
;;(setq exwm-workspace-minibuffer-position 'bottom)
;; Do not forget to enable EXWM. It will start by itself when things are
;; ready. You can put it _anywhere_ in your configuration.
(exwm-enable)
(exwm-systemtray-enable)
(wm-randr)
;; (with-flag nlinum
;; (add-hook 'exwm-mode-hook 'disable-nlinum))
)
(provide 'cubes/wm/core)
;;; core.el ends here

View File

@ -1,10 +1,10 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani & Contributors
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://devheroes.codes/FG42/FG42
;; Version: 4.0.0
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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
@ -21,22 +21,21 @@
;;
;;; Commentary:
;;; Code:
(eval-when-compile
(require 'fpkg))
(require 'fg42/core)
(require 'fg42/utils)
(use! eros
"Evaluation Result OverlayS for Emacs Lisp."
:commands eros-mode)
(use! elisp-mode
"Elisp mode."
:hook
((emacs-lisp-mode . rainbow-delimiters-mode)
(emacs-lisp-mode . paredit-mode)
(emacs-lisp-mode . company-mode)
(emacs-lisp-mode . eros-mode)))
(defun fg42/before-initialize ()
"Initialize the package manager before rendering the window instance."
(require 'fpkg/core)
(fpkg/initialize))
(provide 'fg42/langs/elisp)
;;; elisp.el ends here
(defun fg42/initialize ()
"Initialize FG42 after the Emacs window is rendered by loading the user init file."
(when (file-exists-p user-init-file)
(load user-init-file)))
(provide 'fg42)
;;; fg42.el ends here

View File

@ -1,10 +1,10 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani <lxsameer@gnu.org>
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://devheroes.codes/FG42/FG42
;; Version: 4.0.0
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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
@ -25,20 +25,12 @@
(defgroup fg42 nil
"Customize your FG42 instance via this group of configurations.")
(defvar fg42/after-init-hook nil
"The hook tha runs when FG42 finished running the user configuration.")
(defvar fg42/debug-p nil
"The hook tha runs when FG42 finished running the user configuration.")
(defvar fg42-config-dir (or (getenv "FG42_CONFIG_DIR") "~/.fg42")
"Where to store installation specific data.")
(defvar fg42-home (getenv "FG42_HOME")
"The pass to fg42-home.")
(defvar fg42-tmp (concat fg42-config-dir "/tmp"))
(defvar fg42-tmp (concat fg42-home "/tmp"))
(provide 'fg42/core)

115
core/fg42/cube.el Normal file
View File

@ -0,0 +1,115 @@
;;; Cube --- Cube library of FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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:
;; Cubes are the building blocks of any `FG42' editor. Each `cube' is a
;; unit which defines different abilities in a deterministic and idempotent
;; way. Cubes are composable and a composition of cubes creates an editor.
;;
;;; Code:
(require 'seq)
(require 'fg42/utils)
(defmacro defcube (cube-name props &rest body)
"Define a cube with the given CUBE-NAME, a list of PROPS and a BODY."
(declare (indent defun))
;; Make sure that props is a plist and contains the `:docs' key
;; TODO: Maybe use `cl-check-type' here
(when (not (plist-get props :docs))
(error "Missing docs key for '%s' cube" cube-name))
(let ((params-var (intern (format "%s-params" cube-name)))
(active-var (intern (format "%s-active-p" cube-name)))
(pre-lang-server-up-hook (intern (format "%s-pre-lang-server-up-hook" cube-name)))
(post-lang-server-up-hook (intern (format "%s-post-lang-server-up-hook" cube-name)))
(pre-lang-server-down-hook (intern (format "%s-pre-lang-server-down-hook" cube-name)))
(post-lang-server-down-hook (intern (format "%s-post-lang-server-down-hook" cube-name)))
(pre-init-hook (intern (format "%s-pre-init-hook" cube-name)))
(post-init-hook (intern (format "%s-post-init-hook" cube-name))))
`(progn
;; Params variable contains the list of params the is passed to
;; the current cube call
(defvar ,params-var nil
,(format "Parameters for the '%s' cube." cube-name))
;; * Hooks
;; This hook can be used by others to run code just before running that
;; code body
(defvar ,pre-init-hook nil
,(format "The hook that runs befor the '%s' cube initialization." cube-name))
;; This hook can be used by others to run code just after the body of
;; the cube
(defvar ,post-init-hook nil
,(format "The hook that runs after the '%s' cube initialization." cube-name))
;; TODO: Move language server related hooks to lang-server
;; TODO: Provide a way to let different parts of the
;; codebase to create cube hooks
;; ** Language Server
;;; The hook that enables users to change the language server configuration
;;; of the current cube before activating the server
(defvar ,pre-lang-server-up-hook nil
,(format "The hook that runs befor the '%s' cube's language server activates ." cube-name))
;;; The hook to do any post configuration for the lang server of the cube
(defvar ,post-lang-server-up-hook nil
,(format "The hook that runs after the '%s' cube's language server activates." cube-name))
;;; The hook to run code just before the language server is about to shutdown
(defvar ,pre-lang-server-down-hook nil
,(format "The hook that runs befor the '%s' cube's language server shuts down." cube-name))
;;; The hook to run code after the language server successfully shuts down
(defvar ,post-lang-server-down-hook nil
,(format "The hook that runs after the '%s' cube's language server shuts down." cube-name))
(defun ,cube-name (&rest params)
(when (not (boundp (quote ,active-var)))
(progn
;; Mark this cube as active
(setq ,active-var t)
;; Set the parameters in CUBE-NAME-params to be accessable
;; in the body
(setq ,params-var params)
;; Run the pre init hook
(run-hooks (quote ,pre-init-hook))
(message "Initializing '%s' cube." (quote ,cube-name))
;; Run the body
(let ((result (progn ,@body)))
;; Run the post init hook
(run-hooks (quote ,post-init-hook))
result)))))))
(provide 'fg42/cube)
;;; cube.el ends here

View File

@ -1,10 +1,10 @@
;;; Flags --- Flags library of FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani & Contributors
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://devheroes.codes/FG42/FG42
;; Version: 4.0.0
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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
@ -22,7 +22,6 @@
;;; Commentary:
;;; Code:
(require 'cl-lib)
(require 'seq)
(require 'fg42/core)
@ -40,21 +39,20 @@ Flags are defined using the \\[defflag] through out the source code.
To see a list of available flags use \\[fg42/show-all-flags] and to see
the documentation of each flag simply use \\[describe-flag]."
:group 'fg42
:package-version '(FG42 . "4.x")
:package-version '(FG42 . "3.x")
:type '(symbol)
:tag "FG42 Flags")
(defmacro use-flags (flags)
(defmacro use-flags (&rest flags)
"Set the given FLAGS to activate their functionalities in FG42."
`(progn
(setq fg42/flags ,flags)
t))
(setq fg42/flags flags)
t)
(defun fg42/-merge-flags (flags-set &rest new-flags)
"Merge the given NEW-FLAGS into the FLAGS-SET and return the result."
(cl-remove-duplicates
(remove-duplicates
(seq-reduce
(lambda (result flag)
(let ((flag-str (symbol-name flag)))
@ -82,26 +80,14 @@ For example, `(fg42/merge-flags (list f1 f2 f3) f4 -f2)' will return `(f1 f3 f4)
`(fg42/-merge-flags ,flags-set ,@(mapcar (lambda (x) `',x) new-flags)))
(defmacro fg42/merge-with-default-flags (&rest new-flags)
"Merge the given list of NEW-FLAGS with default flags of FG42 and return the new set."
`(fg42/merge-flags fg42/flags ,@new-flags))
(defmacro defflag (flag-name docstring &optional default-value)
"Define a new flag FLAG-NAME with the given DOCSTRING.
If the DEFAULT-VALUE is a non nil value, then the flag will be
added to the active flags list."
(declare (doc-string 2) (indent defun))
(let ((var-name (intern (format "fg42/-flag-%s" (symbol-name flag-name))))
(set-default (when default-value
`((add-to-list 'fg42/flags ',flag-name)))))
(defmacro defflag (flag-name docstring)
"Define a new flag FLAG-NAME with the given DOCSTRING."
(let ((var-name (intern (format "fg42/-flag-%s" flag-name))))
`(if (boundp ',var-name)
(warn (format "Flag name `%s' already defined" ,(format "%s" flag-name)))
(warn (foramt "Flag name `%s' already defined" ,flag-name))
(progn
(defvar ,var-name t)
(add-to-list 'fg42/available-flags ',flag-name)
,@set-default))))
(add-to-list 'fg42/available-flags ',flag-name)))))
(defmacro when-flag (flag &rest body)
@ -109,11 +95,12 @@ added to the active flags list."
(declare (indent defun))
;; The `cube-local-flags' variable here is going to be
;; defined in cubes to hold the local flags for each cube
(if (not (and (boundp 'cube-local-flags)
(member flag cube-local-flags)))
`(progn ,@body)
`(when (member ',flag fg42/flags)
,@body)))
(if (and (boundp 'cube-local-flags)
(member flag cube-local-flags))
`,@body
`(if (member ',flag fg42/flags)
,body
nil)))
(defmacro if-flag (flag then else)
@ -123,8 +110,8 @@ added to the active flags list."
;; defined in cubes to hold the local flags for each cube
(if (and (boundp 'cube-local-flags)
(member flag cube-local-flags))
then
`(if (member ',flag fg42/flags)
`,@then
`(if (member ',flag fg42/flags)
,then
,else)))

30
core/fg42/lang-servers.el Normal file
View File

@ -0,0 +1,30 @@
;;; Flags --- Flags library of FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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/flags)
(provide 'lang-servers)
;;; lang-servers.el ends here

View File

@ -1,10 +1,10 @@
;;; Utils --- Utils library of FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2024 Sameer Rahmani <lxsameer@gnu.org>
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://devheroes.codes/FG42/FG42
;; Version: 4.0.0
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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
@ -97,6 +97,29 @@ with is the buffer."
,@form))
;; TODO: A good candidate for an inline function
(defun find-value-for (lst key)
"Return the value of the given KEY in the given LST.
For example for a list like (list :x 4 :y 5) we can find the value of
`:x' by doing `(get-value-for lst :x)'."
(let ((pairs (seq-partition lst 2)))
(let ((pair (assq key pairs)))
(when pair
(cadr pair)))))
(defun comp (&rest fns)
"Compose the given list of FNS into one function that accepts multiple values.
For example:
(funcall (compose (lambda (x) (+ 1 x)) (lambda (x) (* x s))) 5)
or
(funcall (compose #'some-fn #'message) some-value)"
(lambda (&rest values)
(cl-reduce 'funcall (butlast fns)
:from-end t
:initial-value (apply (car (last fns)) values))))
(defun path-join (&rest paths)
"Join the given PATHS."
(apply #'concat
@ -134,27 +157,16 @@ last item in second form, etc."
(: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 load-user-config (file)
"Load the given FILE as user config file."
(if (file-exists-p file)
(load-file file)))
(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)))
(defmacro autoload-cube (fn file docstring)
"A wrapper for autloading FN at FILE with the given DOCSTRING.
This macro looks inside of the cubes directories."
`(autoload ,fn (expand-file-name (format "core/cubes/%s" ,file) fg42-home) ,docstring))
(provide 'fg42/utils)

View File

@ -1,6 +1,6 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;; fpkg --- a simple package manager for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2010-2024 Sameer Rahmani <lxsameer@gnu.org>
;; Copyright (C) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; Keywords: lisp fg42 IDE package manager
@ -20,14 +20,23 @@
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;; This file contains all the dependencies of FG42 v4 in no particular order.
;; Whether we use a package during runtime or not we will build everything
;; and decide what to load at runtime.
;;
;; We fetch these dependencies using Nix via the emacs-overlay.
;; Simple package manager for FG42
;;
;;; Code:
(provide 'fg42/direnv)
;;; direnv.el ends here
;;(require 'use-package)
(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)))
`(use-package ,pkg :straight ,@details :defer t)
`(use-package ,pkg :straight t :defer t)))
(provide 'fpkg)
;;; fpkg.el ends here

View File

@ -1,6 +1,6 @@
;;; fpkg --- a simple package manager for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2010-2024 Sameer Rahmani <lxsameer@gnu.org>
;; Copyright (C) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; Keywords: lisp fg42 IDE package manager
@ -29,38 +29,36 @@
(defvar bootstrap-version 5)
(defcustom fpkg-package-directory (concat fg42-home "/.fpkg")
"Specify the directory to store all the dependencies."
:group 'fpkg
:type 'string)
(defun fpkg/install-and-load-use-package ()
"Install and load the `use-package' in compile time."
"Install and load the use-package in compile time."
;; TODO Enable use-package on compile time
;;(eval-when-compile)
(if fg42-use-nix
(setq use-package-always-ensure nil)
(progn
(setq use-package-always-ensure t)
(straight-use-package 'use-package)))
(straight-use-package 'use-package)
(setq use-package-always-ensure t)
(require 'use-package))
(defun fpkg/initialize ()
"Initialize FPKG."
(if (null fg42-use-nix)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)))
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage)
(fpkg/install-and-load-use-package))
(unless (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/install-and-load-use-package)))
(provide 'fpkg/core)
;;; core.el ends here

61
dev.org Normal file
View File

@ -0,0 +1,61 @@
#+TITLE: FG42 Development
#+AUTHOR: Sameer Rahmani
#+SEQ_TODO: TODO(t/!) NEXT(n/!) BLOCKED(b@/!) | DONE(d%) WONT_DO(c@/!) FAILED(f@/!)
#+TAGS: DOCS(d) EXAMPLES(e) Misc(m) Lib(l)
#+STARTUP: logdrawer logdone logreschedule indent content align constSI entitiespretty nolatexpreview
#+OPTIONS: tex:t
#+HTML_MATHJAX: align: left indent: 5em tagside: left font: Neo-Eule
#+LATEX_CLASS: article
#+LATEX_CLASS_OPTIONS: [a4paper]
#+LATEX_HEADER: \usepackage{tcolorbox}
#+LATEX_HEADER: \usepackage{mathabx}
#+LATEX_HEADER: \newtcolorbox{infobox}[2][]{colback=cyan!5!white,before skip=14pt,after skip=8pt,colframe=cyan!75!black,sharp corners,title={#2},#1}
This document is dedicated to the resources, TODOs, research summary, ideas and whatever that is
part of the development process.
* Development Goals
In the past we tried many different ideas and features but since we didn't have a clear goal set,
we couldn't really make it work and differentiate good ideas from bad ones.
** Who are the target audience?
On the first level, I should feel comfortable with it.
** What set of features are important to us?
* Tools
** Straight
We gave it a shot before and it didn't work out but our requirements were different back then.
We should give it a shot again
* Libraries
** Midnight mode
It's a cool library that run some action every midnight, we can use it to clean up old buffers
or other maintenance jobs
* Tasks
** TODO Reformat the modeline
** TODO Create a macro similar to =with-ability= to run a block of code only if the given cube was active
** TODO Enable =straight= and =use-package= integration on compile time. Checout out =fpkg/core.el=
* Things that didn't work out
- rbenv
- helm
- linum
- tabbar
- ido
- ivy
- spaceline
- doom-modeline
- smart-mode-line
- desktop-mode
- jedi
- file-browser
- dired+
- guru
- emoji
- elpy
- github
- versioned-backup

1
docs/CNAME Normal file
View File

@ -0,0 +1 @@
fg42.lxsameer.com

15
docs/Gemfile Normal file
View File

@ -0,0 +1,15 @@
source 'https://rubygems.org'
gem 'guard'
gem 'guard-shell'
gem 'asciidoctor'
gem 'webrick'
gem 'rake'
gem 'coderay'
gem 'prawn'
gem 'addressable'
gem 'prawn-svg'
gem 'prawn-templates'
gem 'asciidoctor-pdf'
gem 'asciidoctor-epub3'

117
docs/Gemfile.lock Normal file
View File

@ -0,0 +1,117 @@
GEM
remote: https://rubygems.org/
specs:
Ascii85 (1.0.3)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
afm (0.2.2)
asciidoctor (1.5.6.2)
asciidoctor-epub3 (1.5.0.alpha.8)
asciidoctor (~> 1.5.0)
gepub (~> 0.6.9.2)
thread_safe (~> 0.3.6)
asciidoctor-pdf (1.5.0.alpha.16)
asciidoctor (>= 1.5.0)
prawn (>= 1.3.0, < 2.3.0)
prawn-icon (= 1.3.0)
prawn-svg (>= 0.21.0, < 0.28.0)
prawn-table (= 0.2.2)
prawn-templates (>= 0.0.3, <= 0.1.1)
safe_yaml (~> 1.0.4)
thread_safe (~> 0.3.6)
treetop (= 1.5.3)
coderay (1.1.2)
css_parser (1.6.0)
addressable
ffi (1.9.23)
formatador (0.2.5)
gepub (0.6.9.2)
nokogiri (~> 1.6.1)
rubyzip (>= 1.1.1)
guard (2.14.2)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
lumberjack (>= 1.0.12, < 2.0)
nenv (~> 0.1)
notiffany (~> 0.0)
pry (>= 0.9.12)
shellany (~> 0.0)
thor (>= 0.18.1)
guard-compat (1.2.1)
guard-shell (0.7.1)
guard (>= 2.0.0)
guard-compat (~> 1.0)
hashery (2.1.2)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
lumberjack (1.0.13)
method_source (0.9.0)
mini_portile2 (2.1.0)
nenv (0.3.0)
nokogiri (1.6.8.1)
mini_portile2 (~> 2.1.0)
notiffany (0.1.1)
nenv (~> 0.1)
shellany (~> 0.0)
pdf-core (0.7.0)
pdf-reader (2.1.0)
Ascii85 (~> 1.0.0)
afm (~> 0.2.1)
hashery (~> 2.0)
ruby-rc4
ttfunk
polyglot (0.3.5)
prawn (2.2.2)
pdf-core (~> 0.7.0)
ttfunk (~> 1.5)
prawn-icon (1.3.0)
prawn (>= 1.1.0, < 3.0.0)
prawn-svg (0.27.1)
css_parser (~> 1.3)
prawn (>= 0.11.1, < 3)
prawn-table (0.2.2)
prawn (>= 1.3.0, < 3.0.0)
prawn-templates (0.1.1)
pdf-reader (~> 2.0)
prawn (~> 2.2)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
public_suffix (3.0.2)
rake (12.3.1)
rb-fsevent (0.10.3)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
ruby-rc4 (0.1.5)
ruby_dep (1.5.0)
rubyzip (1.2.1)
safe_yaml (1.0.4)
shellany (0.0.1)
thor (0.20.0)
thread_safe (0.3.6)
treetop (1.5.3)
polyglot (~> 0.3)
ttfunk (1.5.1)
webrick (1.4.2)
PLATFORMS
ruby
DEPENDENCIES
addressable
asciidoctor
asciidoctor-epub3
asciidoctor-pdf
coderay
guard
guard-shell
prawn
prawn-svg
prawn-templates
rake
webrick
BUNDLED WITH
1.16.1

18
docs/Guardfile Normal file
View File

@ -0,0 +1,18 @@
Bundler.require :default
guard 'shell' do
watch(/[^\.].*\.adoc$/) do |m|
Asciidoctor .convert_file(
'index.adoc', to_dir: '_build/', mkdirs: true, safe: :safe,
backend: :html5, header_footer: true, sourcemap: true,
stylesdir: 'stylesheets',
base_dir: './',
attributes: {
'stylesdir' => 'styles',
'imagesdir' => './images',
'nofooter' => true,
'allow-uri-read' => true,
'stylesheet' => 'style.css'
})
end
end

75
docs/Rakefile Normal file
View File

@ -0,0 +1,75 @@
require 'webrick'
require 'asciidoctor'
require 'asciidoctor-pdf'
require 'asciidoctor-epub3'
desc 'Run doc webserver'
task :serve do
root = File.expand_path './_build/'
`cp images ./_build/images -rv`
server = WEBrick::HTTPServer.new Port: 3000, DocumentRoot: root
trap 'INT' do server.shutdown end
server.start
end
desc 'compile the docs'
task :compile do
Asciidoctor .convert_file(
'index.adoc', to_dir: '_build/', mkdirs: true, safe: :safe,
backend: :html5, header_footer: true, sourcemap: true,
stylesdir: 'stylesheets',
base_dir: './',
attributes: {
'stylesdir' => 'styles',
'imagesdir' => './images',
'nofooter' => true,
'allow-uri-read' => true,
'stylesheet' => 'style.css'
})
`cp images ./_build/images -rv`
Asciidoctor .convert_file(
'index.adoc', to_dir: '_build/', mkdirs: true, safe: :safe,
backend: :pdf, header_footer: true, sourcemap: true, to_file: 'hellhound.pdf',
stylesdir: 'stylesheets',
base_dir: './',
attributes: {
'stylesdir' => 'styles',
'imagesdir' => './images',
'nofooter' => true,
'allow-uri-read' => true,
'stylesheet' => 'style.css'
})
Asciidoctor .convert_file(
'index.adoc', to_dir: '_build/', mkdirs: true, safe: :safe,
backend: :epub3, header_footer: true, sourcemap: true, to_file: 'hellhound.epub',
stylesdir: 'stylesheets',
base_dir: './',
attributes: {
'stylesdir' => 'styles',
'imagesdir' => './images',
'nofooter' => true,
'allow-uri-read' => true,
'stylesheet' => 'style.css'
})
puts "You need to set KINDLEGEN env."
Asciidoctor .convert_file(
'index.adoc', to_dir: '_build/', mkdirs: true, safe: :safe,
backend: :epub3, header_footer: true, sourcemap: true, to_file: 'hellhound.mobi',
stylesdir: 'stylesheets',
base_dir: './',
attributes: {
'ebook-format' => 'kf8',
'stylesdir' => 'styles',
'imagesdir' => './images',
'nofooter' => true,
'allow-uri-read' => true,
'front-cover-image' => 'image:cover.svg[Front Cover,1050,1050]',
'stylesheet' => 'style.css'
})
`cp images ./_build/ -rv`
`rm -rf hellhound-kf8.epub`
end
task default: :serve

View File

@ -0,0 +1,61 @@
[appendix]
= Contributor Covenant Code of Conduct
== Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers
pledge to making participation in our project and our community a harassment-free experience for everyone,
regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and orientation.
== Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
== Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to
take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits,
code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban
temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening,
offensive, or harmful.
== Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing
the project or its community. Examples of representing a project or community include using an official project
e-mail address, posting via an official social media account, or acting as an appointed representative at an
online or offline event. Representation of a project may be further defined and clarified by project maintainers.
== Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project
team at devs@codamic.tech. The project team will review and investigate all complaints, and will respond in
a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality
with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent
repercussions as determined by other members of the project's leadership.
== Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at http://contributor-covenant.org/version/1/4[version]
http://contributor-covenant.org[homepage]
http://contributor-covenant.org/version/1/4/[version]

View File

@ -0,0 +1,59 @@
[appendix]
= Contributing to HellHound
Wow, thanks for your interest in helping out with HellHound. Let this document
serve as your guide.
== Looking for work?
If you're looking for a task to work on, check out the
http://github.com/Codamic/hellhound/issues?labels=TODO[TODO] in our issues.
Less defined tasks will be marked with the
http://github.com/Codamic/hellhound/issues?labels=discuss[discuss label]. Jump in here if you want to be
a part of something big.
== New Features
HellHound is the thinking persons framework, so every contribution starts with
some *deeeep* thought. Finished?
Alright, your next step is to start a discussion.
Create an https://github.com/Codamic/hellhound/issues/new[issue] to start
a conversation. Tell us what you're trying to accomplish and how you think you
might do it. If all is well, we'll probably give you the :thumbsup: to
start developing.
== Bugs
Of course, if you run into any straight-up bugs or weirdness feel free to skip
the thinking (or at least too much of it) and immediately submit an https://github.com/codamic/hellhound/issues/new[issue].
We have an issue template in place that will ask you some details
about the platform you are running and how to reproduce the bug. (If
you can reproduce it reliably. If not, go ahead and file the issue
anyway so we can start looking at it.)
Some of the usual stuff we'll want to know:
* What happened?
** "I manifested a being from the outer dimensions."
* What did you expect to happen?
** "Hello, world."
* How can you reprodice it?
** "I created a new HellHound service with the template, then installed some code that Bob Howard gave me."
* What operating system and version are you using?
** e.g. "OS X 10.8"
* What version of Clojure, Java, and Leiningen or Boot are you using?
** e.g. "Leiningen 2.5.2 on Java 1.8.0_u40 Java HotSpot(TM) 64-Bit Server VM"
* What HellHound version are you using?
** e.g. "0.5.0"
** or, for a SNAPSHOT: "0.5.1-SNAPSHOT at d0cf2b4"
Even better, include a link to a gist or repository where we can jump straight
to the problem.
== Tests
<PLACEHOLDER TEXT>

View File

@ -0,0 +1,31 @@
== Getting Started
In this section i'm going to walk you through the installation process of *FG42* and some basic usage. Also
If you already know how to use Emacs you just need the installation subsection of this section.
=== Installation
In order to run *FG42* you need *GNU Emacs >= 25*. FG42 uses several extensions internally
which each of the has different external dependencies. To gain more information about external
dependencies ( If we failed to tell you inside the **FG42** ) just run the `describe-extension`
command. Also I have plans in near future to create some packages for popular gnu/linux distros
and MacOS as well, but untill then you have to take care of the external dependencies by yourself.
In order to install **FG42**, issue the following commands:
[source,bash,linum]
----
# clonse the FG42 repository in ~/.fg42 directory
git clone git://gitlab.com/FG42/FG42.git ~/.fg42/
# You can clone it where ever your want
cd ~/.fg42/
# You need to be sudoer, the install script will ask for your password.
make install
----
Since the installer script uses `sudo`, during the installation process,
you'll have to enter your password. Make sure that you're user account has
a `sudo` access.
=== Execution
If you installed FG42 using git your installation does not contain any elisp package. So, when for the
first time you executes FG42 it detects the missing libraries and download them from Melpa. It might
take a while depends on your internet connection.

0
docs/images/.keep Normal file
View File

72
docs/index.adoc Normal file
View File

@ -0,0 +1,72 @@
= FG42 Editor
:Revision: 1.0.0-alpha3
:Author: Sameer Rahmani (@lxsameer)
:Email: <lxsameer@gnu.org>
:homepage: http://fg42.lxsameer.com
:icons: font
:iconsfont: font-awesome
:sectanchors: true
:description: The ultimate Editor for true believers.
:toc: macro
:toc: left
:toclevels: 3
:toc-title: FG42 Documentation
:doctype: book
:sectnumlevels: 3
:keywords: Emacs, Bundle, Editor, IDE, GNU, Programming
:docinfo: shared
:type: reference
:source-highlighter: coderay
:imagesdir: ./images/
ifdef::backend-html5[]
image::https://gitlab.com/FG42/FG42/raw/master/share/icons/hicolor/128x128/apps/fg42.png[FG42,align="center"]
++++
<div class="center-aligned download-btns">
<a href="//gitlab.com/FG42/FG42" class="lxbtn btn-success">
<i class="fa fa-github"></i>
Github
</a>
<a href="/guides/hellhound.epub" class="lxbtn btn-success">
<i class="fa fa-download"></i>
Download
</a>
</div>
++++
endif::[]
---
:sectnums:
== What is FG42
*FG42* is a free editor which has built on top of link:https://www.gnu.org/software/emacs/[mighty GNU/Emacs] editor. I you're
an Emacs user you're going to find FG42 the ultimate editor for an Emacs guru. But if you're not a user of Emacs afraid no more,
Your going to enjoy FG42 as well.
=== Goals
I started FG42 out of my personal need and it grew since then. I refactored the whole thing once and came up with a better
API for developing it. So my first goal is to share my own tool with other people who showed lots of interest over these
years and my second goal is to make in available for people who are not necessarily Emacs users as well.
// Getting Started
include::getting_started/index.adoc[leveloffset=+1]
// Credit - Appendix 1
include::credit.adoc[leveloffset=+1]
// Appendix 2
include::appendix/contribute.adoc[leveloffset=+1]
// Appendix 3
include::appendix/code_of_conduct.adoc[leveloffset=+1]
[colophon]
= Colophon
The FG42 User Manual
(C) 2010-2018 by Sameer Rahmani <lxsameer@gnu.org>
Created in Asciidoctor, Debian Unstable and FG42 Editor.

811
docs/styles/style.css Normal file
View File

@ -0,0 +1,811 @@
@import url("https://fonts.googleapis.com/css?family=Open+Sans");
/*! normalize.css v2.1.2 | MIT License | git.io/normalize */
/* ========================================================================== HTML5 display definitions ========================================================================== */
/** Correct `block` display not defined in IE 8/9. */
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; }
/** Correct `inline-block` display not defined in IE 8/9. */
audio, canvas, video { display: inline-block; }
/** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */
audio:not([controls]) { display: none; height: 0; }
/** Address `[hidden]` styling not present in IE 8/9. Hide the `template` element in IE, Safari, and Firefox < 22. */
[hidden], template { display: none; }
script { display: none !important; }
/* ========================================================================== Base ========================================================================== */
/** 1. Set default font family to sans-serif. 2. Prevent iOS text size adjust after orientation change, without disabling user zoom. */
html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ }
/** Remove default margin. */
body { margin: 0; }
/* ========================================================================== Links ========================================================================== */
/** Remove the gray background color from active links in IE 10. */
a { background: transparent; }
/** Address `outline` inconsistency between Chrome and other browsers. */
a:focus { outline: thin dotted; }
/** Improve readability when focused and also mouse hovered in all browsers. */
a:active, a:hover { outline: 0; }
/* ========================================================================== Typography ========================================================================== */
/** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome. */
h1 { font-size: 2em; margin: 0.67em 0; }
/** Address styling not present in IE 8/9, Safari 5, and Chrome. */
abbr[title] { border-bottom: 1px dotted; }
/** Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */
b, strong { font-weight: bold; }
/** Address styling not present in Safari 5 and Chrome. */
dfn { font-style: italic; }
/** Address differences between Firefox and other browsers. */
hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; }
/** Address styling not present in IE 8/9. */
mark { background: #ff0; color: #000; }
/** Correct font family set oddly in Safari 5 and Chrome. */
code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; }
/** Improve readability of pre-formatted text in all browsers. */
pre { white-space: pre-wrap; }
/** Set consistent quote types. */
q { quotes: "\201C" "\201D" "\2018" "\2019"; }
/** Address inconsistent and variable font size in all browsers. */
small { font-size: 80%; }
/** Prevent `sub` and `sup` affecting `line-height` in all browsers. */
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sup { top: -0.5em; }
sub { bottom: -0.25em; }
/* ========================================================================== Embedded content ========================================================================== */
/** Remove border when inside `a` element in IE 8/9. */
img { border: 0; }
/** Correct overflow displayed oddly in IE 9. */
svg:not(:root) { overflow: hidden; }
/* ========================================================================== Figures ========================================================================== */
/** Address margin not present in IE 8/9 and Safari 5. */
figure { margin: 0; }
/* ========================================================================== Forms ========================================================================== */
/** Define consistent border, margin, and padding. */
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
/** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */
legend { border: 0; /* 1 */ padding: 0; /* 2 */ }
/** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */
button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ }
/** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */
button, input { line-height: normal; }
/** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */
button, select { text-transform: none; }
/** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */
button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ }
/** Re-set default cursor for disabled elements. */
button[disabled], html input[disabled] { cursor: default; }
/** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */
input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ }
/** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */
input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; }
/** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
/** Remove inner padding and border in Firefox 4+. */
button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; }
/** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */
textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ }
/* ========================================================================== Tables ========================================================================== */
/** Remove most spacing between table cells. */
table { border-collapse: collapse; border-spacing: 0; }
meta.foundation-mq-small { font-family: "only screen and (min-width: 768px)"; width: 768px; }
meta.foundation-mq-medium { font-family: "only screen and (min-width:1280px)"; width: 1280px; }
meta.foundation-mq-large { font-family: "only screen and (min-width:1440px)"; width: 1440px; }
*, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
html, body { font-size: 100%; }
body { background: white; color: #3f3f3f; padding: 0; margin: 0; font-family: "Open Sans", "DejaVu Serif", serif; font-weight: normal; font-style: normal; line-height: 1; position: relative; cursor: auto; }
a:hover { cursor: pointer; }
img, object, embed { max-width: 100%; height: auto; }
object, embed { height: 100%; }
img { -ms-interpolation-mode: bicubic; }
#map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { max-width: none !important; }
.left { float: left !important; }
.right { float: right !important; }
.text-left { text-align: left !important; }
.text-right { text-align: right !important; }
.text-center { text-align: center !important; }
.text-justify { text-align: justify !important; }
.hide { display: none; }
.antialiased { -webkit-font-smoothing: antialiased; }
img { display: inline-block; vertical-align: middle; }
textarea { height: auto; min-height: 50px; }
select { width: 100%; }
object, svg { display: inline-block; vertical-align: middle; }
.center { margin-left: auto; margin-right: auto; }
.spread { width: 100%; }
p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { font-size: 1.21875em; line-height: 1.6; }
.subheader, .admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { line-height: 1.45; color: #c34113; font-weight: normal; margin-top: 0; margin-bottom: 0.25em; }
/* Typography resets */
div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; direction: ltr; }
/* Default Link Styles */
a { color: #2156a5; text-decoration: underline; line-height: inherit; }
a:hover, a:focus { color: #1d4b8f; }
a img { border: none; }
/* Default paragraph styles */
p { text-align: justify; font-family: inherit; font-weight: normal; font-size: 1em; line-height: 1.6; margin-bottom: 1.25em; text-rendering: optimizeLegibility; }
p aside { font-size: 0.875em; line-height: 1.35; font-style: italic; }
/* Default header styles */
h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { font-family: "Open Sans", "DejaVu Sans", sans-serif; font-weight: 300; font-style: normal; color: #E95420; text-rendering: optimizeLegibility; margin-top: 1em; margin-bottom: 0.5em; line-height: 1.0125em; }
h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small { font-size: 60%; color: #e99b8f; line-height: 0; }
h1 { font-size: 2.125em; }
h2 { font-size: 1.6875em; }
h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.375em; }
h4 { font-size: 1.125em; }
h5 { font-size: 1.125em; }
h6 { font-size: 1em; }
hr { border: solid #ddddd8; border-width: 1px 0 0; clear: both; margin: 1.25em 0 1.1875em; height: 0; }
/* Helpful Typography Defaults */
em, i { font-style: italic; line-height: inherit; }
strong, b { font-weight: bold; line-height: inherit; }
small { font-size: 60%; line-height: inherit; }
code { font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace; font-weight: normal; color: rgba(0, 0, 0, 0.9); }
/* Lists */
ul, ol, dl { font-size: 1em; line-height: 1.6; margin-bottom: 1.25em; list-style-position: outside; font-family: inherit; }
ul, ol { margin-left: 1.5em; }
ul.no-bullet, ol.no-bullet { margin-left: 1.5em; }
/* Unordered Lists */
ul li ul, ul li ol { margin-left: 1.25em; margin-bottom: 0; font-size: 1em; /* Override nested font-size change */ }
ul.square li ul, ul.circle li ul, ul.disc li ul { list-style: inherit; }
ul.square { list-style-type: square; }
ul.circle { list-style-type: circle; }
ul.disc { list-style-type: disc; }
ul.no-bullet { list-style: none; }
/* Ordered Lists */
ol li ul, ol li ol { margin-left: 1.25em; margin-bottom: 0; }
/* Definition Lists */
dl dt { margin-bottom: 0.3125em; font-weight: bold; }
dl dd { margin-bottom: 1.25em; }
/* Abbreviations */
abbr, acronym { text-transform: uppercase; font-size: 90%; color: #3f3f3f; border-bottom: 1px dotted #ddd; cursor: help; }
abbr { text-transform: none; }
/* Blockquotes */
blockquote { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #ddd; }
blockquote cite { display: block; font-size: 0.9375em; color: rgba(0, 0, 0, 0.6); }
blockquote cite:before { content: "\2014 \0020"; }
blockquote cite a, blockquote cite a:visited { color: rgba(0, 0, 0, 0.6); }
blockquote, blockquote p { line-height: 1.6; color: rgba(0, 0, 0, 0.85); }
/* Microformats */
.vcard { display: inline-block; margin: 0 0 1.25em 0; border: 1px solid #ddd; padding: 0.625em 0.75em; }
.vcard li { margin: 0; display: block; }
.vcard .fn { font-weight: bold; font-size: 0.9375em; }
.vevent .summary { font-weight: bold; }
.vevent abbr { cursor: auto; text-decoration: none; font-weight: bold; border: none; padding: 0 0.0625em; }
@media only screen and (min-width: 768px) { h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.2; }
h1 { font-size: 2.75em; }
h2 { font-size: 2.3125em; }
h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.6875em; }
h4 { font-size: 1.4375em; } }
/* Tables */
table { background: #fff; margin-bottom: 1.25em; border: solid 1px #dedede; }
table thead, table tfoot { background: #f7f8f7; font-weight: bold; }
table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { padding: 0.5em 0.625em 0.625em; font-size: inherit; color: #3f3f3f; text-align: left; }
table tr th, table tr td { padding: 0.5625em 0.625em; font-size: inherit; color: #3f3f3f; }
table tr.even, table tr.alt, table tr:nth-of-type(even) { background: #f8f8f7; }
table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { display: table-cell; line-height: 1.6; }
body { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; tab-size: 4; }
h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.2; word-spacing: -0.05em; }
h1 strong, h2 strong, h3 strong, #toctitle strong, .sidebarblock > .content > .title strong, h4 strong, h5 strong, h6 strong { font-weight: 400; }
.clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; }
.clearfix:after, .float-group:after { clear: both; }
*:not(pre) > code { font-size: 0.9375em; font-style: normal !important; letter-spacing: 0; padding: 0.1em 0.5ex; word-spacing: -0.15em; background-color: #f7f7f8; -webkit-border-radius: 4px; border-radius: 4px; line-height: 1.45; text-rendering: optimizeSpeed; word-wrap: break-word; }
*:not(pre) > code.nobreak { word-wrap: normal; }
*:not(pre) > code.nowrap { white-space: nowrap; }
pre, pre > code { line-height: 1.45; color: rgba(0, 0, 0, 0.9); font-family: "Droid Sans Mono", "DejaVu Sans Mono", "Monospace", monospace; font-weight: normal; text-rendering: optimizeSpeed; }
em em { font-style: normal; }
strong strong { font-weight: normal; }
.keyseq { color: #727272; }
kbd { font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace; display: inline-block; color: #3f3f3f; font-size: 0.65em; line-height: 1.45; background-color: #f7f7f7; border: 1px solid #ccc; -webkit-border-radius: 3px; border-radius: 3px; -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; margin: 0 0.15em; padding: 0.2em 0.5em; vertical-align: middle; position: relative; top: -0.1em; white-space: nowrap; }
.keyseq kbd:first-child { margin-left: 0; }
.keyseq kbd:last-child { margin-right: 0; }
.menuseq, .menuref { color: #000; }
.menuseq b:not(.caret), .menuref { font-weight: inherit; }
.menuseq { word-spacing: -0.02em; }
.menuseq b.caret { font-size: 1.25em; line-height: 0.8; }
.menuseq i.caret { font-weight: bold; text-align: center; width: 0.45em; }
b.button:before, b.button:after { position: relative; top: -1px; font-weight: normal; }
b.button:before { content: "["; padding: 0 3px 0 2px; }
b.button:after { content: "]"; padding: 0 2px 0 3px; }
p a > code:hover { color: rgba(0, 0, 0, 0.9); }
#header, #content, #footnotes, #footer { width: 100%; margin-left: auto; margin-right: auto; margin-top: 0; margin-bottom: 0; max-width: 62.5em; *zoom: 1; position: relative; padding-left: 0.9375em; padding-right: 0.9375em; }
#header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { content: " "; display: table; }
#header:after, #content:after, #footnotes:after, #footer:after { clear: both; }
#content { margin-top: 1.25em; }
#content:before { content: none; }
#header > h1:first-child { color: rgba(0, 0, 0, 0.85); margin-top: 2.25rem; margin-bottom: 0; }
#header > h1:first-child + #toc { margin-top: 8px; border-top: 1px solid #ddddd8; }
#header > h1:only-child, body.toc2 #header > h1:nth-last-child(2) { border-bottom: 1px solid #ddddd8; padding-bottom: 8px; }
#header .details { border-bottom: 1px solid #ddddd8; line-height: 1.45; padding-top: 0.25em; padding-bottom: 0.25em; padding-left: 0.25em; color: rgba(0, 0, 0, 0.6); display: -ms-flexbox; display: -webkit-flex; display: flex; -ms-flex-flow: row wrap; -webkit-flex-flow: row wrap; flex-flow: row wrap; }
#header .details span:first-child { margin-left: -0.125em; }
#header .details span.email a { color: rgba(0, 0, 0, 0.85); }
#header .details br { display: none; }
#header .details br + span:before { content: "\00a0\2013\00a0"; }
#header .details br + span.author:before { content: "\00a0\22c5\00a0"; color: rgba(0, 0, 0, 0.85); }
#header .details br + span#revremark:before { content: "\00a0|\00a0"; }
#header #revnumber { text-transform: capitalize; }
#header #revnumber:after { content: "\00a0"; }
#content > h1:first-child:not([class]) { color: rgba(0, 0, 0, 0.85); border-bottom: 1px solid #ddddd8; padding-bottom: 8px; margin-top: 0; padding-top: 1rem; margin-bottom: 1.25rem; }
#toc { border-bottom: 1px solid #efefed; padding-bottom: 0.5em; }
#toc > ul { margin-left: 0.125em; }
#toc ul.sectlevel0 > li > a { font-style: italic; }
#toc ul.sectlevel0 ul.sectlevel1 { margin: 0.5em 0; }
#toc ul { font-family: "Open Sans", "DejaVu Sans", sans-serif; list-style-type: none; }
#toc li { line-height: 1.3334; margin-top: 0.3334em; }
#toc a { text-decoration: none; }
#toc a:active { text-decoration: underline; }
#toctitle { color: #c34113; font-size: 1.2em; }
@media only screen and (min-width: 768px) { #toctitle { font-size: 1.375em; }
body.toc2 { padding-left: 15em; padding-right: 0; }
#toc.toc2 { margin-top: 0 !important; background-color: #f8f8f7; position: fixed; width: 15em; left: 0; top: 0; border-right: 1px solid #efefed; border-top-width: 0 !important; border-bottom-width: 0 !important; z-index: 1000; padding: 1.25em 1em; height: 100%; overflow: auto; }
#toc.toc2 #toctitle { margin-top: 0; margin-bottom: 0.8rem; font-size: 1.2em; }
#toc.toc2 > ul { font-size: 0.9em; margin-bottom: 0; }
#toc.toc2 ul ul { margin-left: 0; padding-left: 1em; }
#toc.toc2 ul.sectlevel0 ul.sectlevel1 { padding-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; }
body.toc2.toc-right { padding-left: 0; padding-right: 15em; }
body.toc2.toc-right #toc.toc2 { border-right-width: 0; border-left: 1px solid #efefed; left: auto; right: 0; } }
@media only screen and (min-width: 1280px) { body.toc2 { padding-left: 20em; padding-right: 0; }
#toc.toc2 { width: 20em; }
#toc.toc2 #toctitle { font-size: 1.375em; }
#toc.toc2 > ul { font-size: 0.95em; }
#toc.toc2 ul ul { padding-left: 1.25em; }
body.toc2.toc-right { padding-left: 0; padding-right: 20em; } }
#content #toc { border-style: solid; border-width: 1px; border-color: #e0e0dc; margin-bottom: 1.25em; padding: 1.25em; background: #f8f8f7; -webkit-border-radius: 4px; border-radius: 4px; }
#content #toc > :first-child { margin-top: 0; }
#content #toc > :last-child { margin-bottom: 0; }
#footer { max-width: 100%; background-color: #fff; padding: 1.25em; border-top: 1px solid #cececf; font-size: 0.9em; }
#footer-text { color: #3f3f3f; line-height: 1.44; }
#content { margin-bottom: 0.625em; }
.sect1 { padding-bottom: 0.625em; }
@media only screen and (min-width: 768px) { #content { margin-bottom: 1.25em; }
.sect1 { padding-bottom: 1.25em; } }
.sect1:last-child { padding-bottom: 0; }
.sect1 + .sect1 { border-top: 1px solid #efefed; }
#content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { position: absolute; z-index: 1001; width: 1.5ex; margin-left: -1.5ex; display: block; text-decoration: none !important; visibility: hidden; text-align: center; font-weight: normal; }
#content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before { content: "\00A7"; font-size: 0.85em; display: block; padding-top: 0.1em; }
#content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover { visibility: visible; }
#content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link { color: #E95420; text-decoration: none; }
#content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover { color: #a53221; }
.audioblock, .imageblock, .literalblock, .listingblock, .stemblock, .videoblock { margin-bottom: 1.25em; }
.admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { text-rendering: optimizeLegibility; text-align: left; font-family: "Open Sans", "DejaVu Serif", serif; font-size: 1rem; font-style: italic; }
table.tableblock > caption.title { white-space: nowrap; overflow: visible; max-width: 0; }
.paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { color: rgba(0, 0, 0, 0.85); }
table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { font-size: inherit; }
.admonitionblock > table { border-collapse: separate; border: 0; background: none; width: 100%; }
.admonitionblock > table td.icon { text-align: center; width: 80px; }
.admonitionblock > table td.icon img { max-width: initial; }
.admonitionblock > table td.icon .title { font-weight: bold; font-family: "Open Sans", "DejaVu Sans", sans-serif; text-transform: uppercase; }
.admonitionblock > table td.content { padding-left: 1.125em; padding-right: 1.25em; border-left: 1px solid #ddddd8; color: rgba(0, 0, 0, 0.6); }
.admonitionblock > table td.content > :last-child > :last-child { margin-bottom: 0; }
.exampleblock > .content { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: white; -webkit-border-radius: 4px; border-radius: 4px; }
.exampleblock > .content > :first-child { margin-top: 0; }
.exampleblock > .content > :last-child { margin-bottom: 0; }
.sidebarblock { border-style: solid; border-width: 1px; border-color: #e0e0dc; margin-bottom: 1.25em; padding: 1.25em; background: #f8f8f7; -webkit-border-radius: 4px; border-radius: 4px; }
.sidebarblock > :first-child { margin-top: 0; }
.sidebarblock > :last-child { margin-bottom: 0; }
.sidebarblock > .content > .title { color: #c34113; margin-top: 0; text-align: center; }
.exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child { margin-bottom: 0; }
.literalblock pre, .listingblock pre:not(.highlight), .listingblock pre[class="highlight"], .listingblock pre[class^="highlight "], .listingblock pre.CodeRay, .listingblock pre.prettyprint { background: #f7f7f8; }
.sidebarblock .literalblock pre, .sidebarblock .listingblock pre:not(.highlight), .sidebarblock .listingblock pre[class="highlight"], .sidebarblock .listingblock pre[class^="highlight "], .sidebarblock .listingblock pre.CodeRay, .sidebarblock .listingblock pre.prettyprint { background: #f2f1f1; }
.literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { -webkit-border-radius: 4px; border-radius: 4px; word-wrap: break-word; padding: 1em; font-size: 0.8125em; }
.literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; }
@media only screen and (min-width: 768px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 0.90625em; } }
@media only screen and (min-width: 1280px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 1em; } }
.literalblock.output pre { color: #f7f7f8; background-color: rgba(0, 0, 0, 0.9); }
.listingblock pre.highlightjs { padding: 0; }
.listingblock pre.highlightjs > code { padding: 1em; -webkit-border-radius: 4px; border-radius: 4px; }
.listingblock pre.prettyprint { border-width: 0; }
.listingblock > .content { position: relative; }
.listingblock code[data-lang]:before { display: none; content: attr(data-lang); position: absolute; font-size: 0.75em; top: 0.425rem; right: 0.5rem; line-height: 1; text-transform: uppercase; color: #999; }
.listingblock:hover code[data-lang]:before { display: block; }
.listingblock.terminal pre .command:before { content: attr(data-prompt); padding-right: 0.5em; color: #999; }
.listingblock.terminal pre .command:not([data-prompt]):before { content: "$"; }
table.pyhltable { border-collapse: separate; border: 0; margin-bottom: 0; background: none; }
table.pyhltable td { vertical-align: top; padding-top: 0; padding-bottom: 0; line-height: 1.45; }
table.pyhltable td.code { padding-left: .75em; padding-right: 0; }
pre.pygments .lineno, table.pyhltable td:not(.code) { color: #999; padding-left: 0; padding-right: .5em; border-right: 1px solid #ddddd8; }
pre.pygments .lineno { display: inline-block; margin-right: .25em; }
table.pyhltable .linenodiv { background: none !important; padding-right: 0 !important; }
.quoteblock { margin: 0 1em 1.25em 1.5em; display: table; }
.quoteblock > .title { margin-left: -1.5em; margin-bottom: 0.75em; }
.quoteblock blockquote, .quoteblock blockquote p { color: rgba(0, 0, 0, 0.85); font-size: 1.15rem; line-height: 1.75; word-spacing: 0.1em; letter-spacing: 0; font-style: italic; text-align: justify; }
.quoteblock blockquote { margin: 0; padding: 0; border: 0; }
.quoteblock blockquote:before { content: "\201c"; float: left; font-size: 2.75em; font-weight: bold; line-height: 0.6em; margin-left: -0.6em; color: #c34113; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); }
.quoteblock blockquote > .paragraph:last-child p { margin-bottom: 0; }
.quoteblock .attribution { margin-top: 0.5em; margin-right: 0.5ex; text-align: right; }
.quoteblock .quoteblock { margin-left: 0; margin-right: 0; padding: 0.5em 0; border-left: 3px solid rgba(0, 0, 0, 0.6); }
.quoteblock .quoteblock blockquote { padding: 0 0 0 0.75em; }
.quoteblock .quoteblock blockquote:before { display: none; }
.verseblock { margin: 0 1em 1.25em 1em; }
.verseblock pre { font-family: "Open Sans", "DejaVu Sans", sans; font-size: 1.15rem; color: rgba(0, 0, 0, 0.85); font-weight: 300; text-rendering: optimizeLegibility; }
.verseblock pre strong { font-weight: 400; }
.verseblock .attribution { margin-top: 1.25rem; margin-left: 0.5ex; }
.quoteblock .attribution, .verseblock .attribution { font-size: 0.9375em; line-height: 1.45; font-style: italic; }
.quoteblock .attribution br, .verseblock .attribution br { display: none; }
.quoteblock .attribution cite, .verseblock .attribution cite { display: block; letter-spacing: -0.025em; color: rgba(0, 0, 0, 0.6); }
.quoteblock.abstract { margin: 0 0 1.25em 0; display: block; }
.quoteblock.abstract blockquote, .quoteblock.abstract blockquote p { text-align: left; word-spacing: 0; }
.quoteblock.abstract blockquote:before, .quoteblock.abstract blockquote p:first-of-type:before { display: none; }
table.tableblock { max-width: 100%; border-collapse: separate; }
table.tableblock td > .paragraph:last-child p > p:last-child, table.tableblock th > p:last-child, table.tableblock td > p:last-child { margin-bottom: 0; }
table.tableblock, th.tableblock, td.tableblock { border: 0 solid #dedede; }
table.grid-all > thead > tr > .tableblock, table.grid-all > tbody > tr > .tableblock { border-width: 0 1px 1px 0; }
table.grid-all > tfoot > tr > .tableblock { border-width: 1px 1px 0 0; }
table.grid-cols > * > tr > .tableblock { border-width: 0 1px 0 0; }
table.grid-rows > thead > tr > .tableblock, table.grid-rows > tbody > tr > .tableblock { border-width: 0 0 1px 0; }
table.grid-rows > tfoot > tr > .tableblock { border-width: 1px 0 0 0; }
table.grid-all > * > tr > .tableblock:last-child, table.grid-cols > * > tr > .tableblock:last-child { border-right-width: 0; }
table.grid-all > tbody > tr:last-child > .tableblock, table.grid-all > thead:last-child > tr > .tableblock, table.grid-rows > tbody > tr:last-child > .tableblock, table.grid-rows > thead:last-child > tr > .tableblock { border-bottom-width: 0; }
table.frame-all { border-width: 1px; }
table.frame-sides { border-width: 0 1px; }
table.frame-topbot { border-width: 1px 0; }
th.halign-left, td.halign-left { text-align: left; }
th.halign-right, td.halign-right { text-align: right; }
th.halign-center, td.halign-center { text-align: center; }
th.valign-top, td.valign-top { vertical-align: top; }
th.valign-bottom, td.valign-bottom { vertical-align: bottom; }
th.valign-middle, td.valign-middle { vertical-align: middle; }
table thead th, table tfoot th { font-weight: bold; }
tbody tr th { display: table-cell; line-height: 1.6; background: #f7f8f7; }
tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p { color: #3f3f3f; font-weight: bold; }
p.tableblock > code:only-child { background: none; padding: 0; }
p.tableblock { font-size: 1em; }
td > div.verse { white-space: pre; }
ol { margin-left: 1.75em; }
ul li ol { margin-left: 1.5em; }
dl dd { margin-left: 1.125em; }
dl dd:last-child, dl dd:last-child > :last-child { margin-bottom: 0; }
ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { margin-bottom: 0.625em; }
ul.checklist, ul.none, ol.none, ul.no-bullet, ol.no-bullet, ol.unnumbered, ul.unstyled, ol.unstyled { list-style-type: none; }
ul.no-bullet, ol.no-bullet, ol.unnumbered { margin-left: 0.625em; }
ul.unstyled, ol.unstyled { margin-left: 0; }
ul.checklist { margin-left: 0.625em; }
ul.checklist li > p:first-child > .fa-square-o:first-child, ul.checklist li > p:first-child > .fa-check-square-o:first-child { width: 1.25em; font-size: 0.8em; position: relative; bottom: 0.125em; }
ul.checklist li > p:first-child > input[type="checkbox"]:first-child { margin-right: 0.25em; }
ul.inline { display: -ms-flexbox; display: -webkit-box; display: flex; -ms-flex-flow: row wrap; -webkit-flex-flow: row wrap; flex-flow: row wrap; list-style: none; margin: 0 0 0.625em -1.25em; }
ul.inline > li { margin-left: 1.25em; }
.unstyled dl dt { font-weight: normal; font-style: normal; }
ol.arabic { list-style-type: decimal; }
ol.decimal { list-style-type: decimal-leading-zero; }
ol.loweralpha { list-style-type: lower-alpha; }
ol.upperalpha { list-style-type: upper-alpha; }
ol.lowerroman { list-style-type: lower-roman; }
ol.upperroman { list-style-type: upper-roman; }
ol.lowergreek { list-style-type: lower-greek; }
.hdlist > table, .colist > table { border: 0; background: none; }
.hdlist > table > tbody > tr, .colist > table > tbody > tr { background: none; }
td.hdlist1, td.hdlist2 { vertical-align: top; padding: 0 0.625em; }
td.hdlist1 { font-weight: bold; padding-bottom: 1.25em; }
.literalblock + .colist, .listingblock + .colist { margin-top: -0.5em; }
.colist > table tr > td:first-of-type { padding: 0.4em 0.75em 0 0.75em; line-height: 1; vertical-align: top; }
.colist > table tr > td:first-of-type img { max-width: initial; }
.colist > table tr > td:last-of-type { padding: 0.25em 0; }
.thumb, .th { line-height: 0; display: inline-block; border: solid 4px #fff; -webkit-box-shadow: 0 0 0 1px #ddd; box-shadow: 0 0 0 1px #ddd; }
.imageblock.left, .imageblock[style*="float: left"] { margin: 0.25em 0.625em 1.25em 0; }
.imageblock.right, .imageblock[style*="float: right"] { margin: 0.25em 0 1.25em 0.625em; }
.imageblock > .title { margin-bottom: 0; }
.imageblock.thumb, .imageblock.th { border-width: 6px; }
.imageblock.thumb > .title, .imageblock.th > .title { padding: 0 0.125em; }
.image.left, .image.right { margin-top: 0.25em; margin-bottom: 0.25em; display: inline-block; line-height: 0; }
.image.left { margin-right: 0.625em; }
.image.right { margin-left: 0.625em; }
a.image { text-decoration: none; display: inline-block; }
a.image object { pointer-events: none; }
sup.footnote, sup.footnoteref { font-size: 0.875em; position: static; vertical-align: super; }
sup.footnote a, sup.footnoteref a { text-decoration: none; }
sup.footnote a:active, sup.footnoteref a:active { text-decoration: underline; }
#footnotes { padding-top: 0.75em; padding-bottom: 0.75em; margin-bottom: 0.625em; }
#footnotes hr { width: 20%; min-width: 6.25em; margin: -0.25em 0 0.75em 0; border-width: 1px 0 0 0; }
#footnotes .footnote { padding: 0 0.375em 0 0.225em; line-height: 1.3334; font-size: 0.875em; margin-left: 1.2em; margin-bottom: 0.2em; }
#footnotes .footnote a:first-of-type { font-weight: bold; text-decoration: none; margin-left: -1.05em; }
#footnotes .footnote:last-of-type { margin-bottom: 0; }
#content #footnotes { margin-top: -0.625em; margin-bottom: 0; padding: 0.75em 0; }
.gist .file-data > table { border: 0; background: #fff; width: 100%; margin-bottom: 0; }
.gist .file-data > table td.line-data { width: 99%; }
div.unbreakable { page-break-inside: avoid; }
.big { font-size: larger; }
.small { font-size: smaller; }
.underline { text-decoration: underline; }
.overline { text-decoration: overline; }
.line-through { text-decoration: line-through; }
.aqua { color: #00bfbf; }
.aqua-background { background-color: #00fafa; }
.black { color: black; }
.black-background { background-color: black; }
.blue { color: #0000bf; }
.blue-background { background-color: #0000fa; }
.fuchsia { color: #bf00bf; }
.fuchsia-background { background-color: #fa00fa; }
.gray { color: #606060; }
.gray-background { background-color: #7d7d7d; }
.green { color: #006000; }
.green-background { background-color: #007d00; }
.lime { color: #00bf00; }
.lime-background { background-color: #00fa00; }
.maroon { color: #600000; }
.maroon-background { background-color: #7d0000; }
.navy { color: #000060; }
.navy-background { background-color: #00007d; }
.olive { color: #606000; }
.olive-background { background-color: #7d7d00; }
.purple { color: #600060; }
.purple-background { background-color: #7d007d; }
.red { color: #bf0000; }
.red-background { background-color: #fa0000; }
.silver { color: #909090; }
.silver-background { background-color: #bcbcbc; }
.teal { color: #006060; }
.teal-background { background-color: #007d7d; }
.white { color: #bfbfbf; }
.white-background { background-color: #fafafa; }
.yellow { color: #bfbf00; }
.yellow-background { background-color: #fafa00; }
span.icon > .fa { cursor: default; }
a span.icon > .fa { cursor: inherit; }
.admonitionblock td.icon [class^="fa icon-"] { font-size: 2.5em; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); cursor: default; }
.admonitionblock td.icon .icon-note:before { content: "\f05a"; color: #19407c; }
.admonitionblock td.icon .icon-tip:before { content: "\f0eb"; text-shadow: 1px 1px 2px rgba(155, 155, 0, 0.8); color: #111; }
.admonitionblock td.icon .icon-warning:before { content: "\f071"; color: #bf6900; }
.admonitionblock td.icon .icon-caution:before { content: "\f06d"; color: #bf3400; }
.admonitionblock td.icon .icon-important:before { content: "\f06a"; color: #bf0000; }
.conum[data-value] { display: inline-block; color: #fff !important; background-color: #3f3f3f; -webkit-border-radius: 100px; border-radius: 100px; text-align: center; font-size: 0.75em; width: 1.67em; height: 1.67em; line-height: 1.67em; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-style: normal; font-weight: bold; }
.conum[data-value] * { color: #fff !important; }
.conum[data-value] + b { display: none; }
.conum[data-value]:after { content: attr(data-value); }
pre .conum[data-value] { position: relative; top: -0.125em; }
b.conum * { color: inherit !important; }
.conum:not([data-value]):empty { display: none; }
dt, th.tableblock, td.content, div.footnote { text-rendering: optimizeLegibility; }
h1, h2, p, td.content, span.alt { letter-spacing: -0.01em; }
p strong, td.content strong, div.footnote strong { letter-spacing: -0.005em; }
p, blockquote, dt, td.content, span.alt { font-size: 1.0625rem; }
p { margin-bottom: 1.25rem; }
.sidebarblock p, .sidebarblock dt, .sidebarblock td.content, p.tableblock { font-size: 1em; }
.exampleblock > .content { background-color: #fffef7; border-color: #e0e0dc; -moz-box-shadow: 0 1px 4px #e0e0dc; -webkit-box-shadow: 0 1px 4px #e0e0dc; box-shadow: 0 1px 4px #e0e0dc; }
.imageblock .title { text-align: center; }
.print-only { display: none !important; }
@media print { @page { margin: 1.25cm 0.75cm; }
* { -moz-box-shadow: none !important; -webkit-box-shadow: none !important; box-shadow: none !important; text-shadow: none !important; }
a { color: inherit !important; text-decoration: underline !important; }
a.bare, a[href^="#"], a[href^="mailto:"] { text-decoration: none !important; }
a[href^="http:"]:not(.bare):after, a[href^="https:"]:not(.bare):after { content: "(" attr(href) ")"; display: inline-block; font-size: 0.875em; padding-left: 0.25em; }
abbr[title]:after { content: " (" attr(title) ")"; }
pre, blockquote, tr, img, object, svg { page-break-inside: avoid; }
thead { display: table-header-group; }
svg { max-width: 100%; }
p, blockquote, dt, td.content { font-size: 1em; orphans: 3; widows: 3; }
h2, h3, #toctitle, .sidebarblock > .content > .title, #toctitle, .sidebarblock > .content > .title { page-break-after: avoid; }
#toc, .sidebarblock, .exampleblock > .content { background: none !important; }
#toc { border-bottom: 1px solid #ddddd8 !important; padding-bottom: 0 !important; }
.sect1 { padding-bottom: 0 !important; }
.sect1 + .sect1 { border: 0 !important; }
#header > h1:first-child { margin-top: 1.25rem; }
body.book #header { text-align: center; }
body.book #header > h1:first-child { border: 0 !important; margin: 2.5em 0 1em 0; }
body.book #header .details { border: 0 !important; display: block; padding: 0 !important; }
body.book #header .details span:first-child { margin-left: 0 !important; }
body.book #header .details br { display: block; }
body.book #header .details br + span:before { content: none !important; }
body.book #toc { border: 0 !important; text-align: left !important; padding: 0 !important; margin: 0 !important; }
body.book #toc, body.book #preamble, body.book h1.sect0, body.book .sect1 > h2 { page-break-before: always; }
.listingblock code[data-lang]:before { display: block; }
#footer { background: none !important; padding: 0 0.9375em; }
#footer-text { color: rgba(0, 0, 0, 0.6) !important; font-size: 0.9em; }
.hide-on-print { display: none !important; }
.print-only { display: block !important; }
.hide-for-print { display: none !important; }
.show-for-print { display: inherit !important; } }
.videoblock { text-align: center; }
.videoblock iframe { border: 1px solid #bfbfbf; }
code b.conum {
display: inline-block;
color: #fff!important;
background-color: rgba(0,0,0,.8);
border-radius: 100px;
text-align: center;
font-size: .75em;
width: 1.67em;
height: 1.67em;
line-height: 1.67em;
font-family: "Open Sans","DejaVu Sans",sans-serif;
font-style: normal;
font-weight: bold;
}
.center-aligned {
text-align: center;
}
.download-btns {
padding-top: 20px;
margin-bottom: 30px;
}
.lxbtn {
border-radius: 4px;
padding: 10px 15px;
text-decoration: none !important;
margin: 20px 10px;
}
.btn-primary {
background: #e95420;
color: white;
}
.btn-success {
background: #772953;
color: white;
}
.btn-success:hover, .btn-success:active, .btn-success:visited {
color: white;
}
.btn-success:hover {
background: #511c39;
}
.btn-info {
background: #E29400;
color: white;
}

View File

@ -1,895 +0,0 @@
#+TITLE: Emacs From Scratch - An Emacs tutorial for beginners
#+SEQ_TODO: TODO(t/!) NEXT(n/!) BLOCKED(b@/!) | DONE(d%) CANCELLED(c@/!) FAILED(f@/!)
#+TAGS: READER(r) MISC(m)
#+STARTUP: logdrawer logdone logreschedule indent content align constSI entitiespretty overview
* DONE Episode 1 - Introduction
CLOSED: [2022-01-09 Sun 19:03]
** What is it all about?
- Create an editor, development environment and Window Manager (yeah window manager) and ...
- GNU/Emacs is amazing
- Spread the joy
- Guide for contributors
- A guide for people who wants to learn some Lisp
** The Plan
- Parallel video series to *How to build a compiler with LLVM and MLIR*
- Git branches
- No live coding
- Start from Emacs and Jump to FG42
- Feel free to contribute
** FG42 and a bit of history
- It's my:
+ Editor/IDE
+ Email client
+ Window Manager
+ File Manager
+ Terminal Emulator
+ IRC client (at some point)
+ TODO manager
+ "Office suit" (air qoute)
+ ....
- Started on 2010 in a train
- I'm working on the V3
- Requirements
+ Emacs >= 27.1
- Website: https://fg42.org/
- Repository: https://devheroes.codes/FG42
- Website: https://lxsameer.com
- Email: lxsameer@gnu.org or lxsameer@lxsameer.com
* DONE Episode 2 - Survive on the first day
CLOSED: [2022-02-11 Fri 10:28]
** Why bother?
** Why GNU/Emacs?
*** People might say because of
- Org-mode
- LSP support
- Support for many many languages
- It's lightweight
- Tons of plugins
- ...
*** I'd say
- Coz it's a lisp environment with an editor attached to it
- Lisp is the difference
+ It's super easy to extend/hack emacs
+ In compare to other editors
- You can do pretty much whatever your like in ELisp
- It's like a framework for building an editor
** FAQ
*** What is the difference between Doom, Spacemacs, FG42 and ...?
Different editors based on Emacs
*** Which one should I use?
*** How to install Emacs packages?
** UI Basics & Basic Concepts
- Window
- Frame
- Mode line
- Buffers
- Mini buffer/Echo area
- Point
- Major mode
- Minor mode
** Basic Keybindings
How to read key bindings? Here is an example =C-x M-e 4=, it means press =x= key while
holding =Control= and then press =e= key while pressing down =Alt= and finally press =4=.
- Emacs tutorial =C-h t= (or https://www.gnu.org/software/emacs/tour/)
- Quit emacs =C-x C-c=
- Abort =C-g=
- Get Help =C-h= family
+ =C-h f=
+ =C-h v=
+ =C-h m=
+ =C-h k=
+ =C-h a=
- Run a command (function) =M-x=
- Visit a file =C-x C-f=
- Search in Buffer =C-s=
- Save buffer =C-x C-s=
- Select region =C-SPC=
- Copy =M-w=
- Cut(killing) =C-w=
- Paste(yanking) =C-y=
- Kill buffer =C-x k=
- Switch buffer =C-x b=
- Undo =C-/=
- Eval expression =C-x C-e=
- =describe-mode=
** Lisp basics
- Expressions everywhere
- Code a data structure
- Almost everything in Lisp evaluates to themselves except:
+ lists
+ Symbols
+ ...
- Lisp laws:
1. Everything in Lisp is an expression and evaluation of an expression
means replacing it with its value
2. Almost everything in Lisp evaluates to themselves except:
- Lists
- Symbols
- Quotes
- ...
-
3. List evaluation
* DONE Episode 3 - Lisp Basics
CLOSED: [2022-03-12 Sat 18:38]
** FAQ:
- How to install Emacs?
+ Just make sure to have *Emacs >= 27.1*
- What's the routine to use Emacs ?
+ Don't use Emacs like how you use other Editors.
+ There is no limits(Almost).
- How evaluate forms?
+ *C-x C-e* at the end of any expression and anywhere
+ ielm
+ Batch mode
** So Fare:
*** Lisp rules:
1. Lisp is made of Expressions and they evaluate to a value.
2. All the expression types evaluates to themselves with some exceptions.
3. List evaluation
*** We will continue with Lisp basics for few episodes
** Variables
- How to define variables and constants
- Set the value of a variable
- Global and local scope
- Lexical bindings vs Dynamic bindings
+ =-*- lexical-binding: t; -*-=
** Functions
- How to define functions
- vs macros
- vs special forms
* DONE Episode 4 - Conditionals
CLOSED: [2022-04-09 Sat 11:24]
** What we learned so far
** what is true and what's not
** Let & prog family
** Conditional special forms
- if
- when
- unless
- cond
** Useful forms and functions
- eq
- equal
- and
- not
- or
- ...
** Type Predicts
- numberp
- stringp
- listp
- boundp
- More at https://www.gnu.org/software/emacs/manual/html_node/elisp/Type-Predicates.html
** type-of
* DONE Episode 5 - Lists
CLOSED: [2022-05-18 Wed 12:40]
** What is a list?
- Not a primitive type
- A linked list made out of cons cells
** Cons Cells
- A container for pairs
- CAR
- CDR (could-er)
#+NAME: ep-5-cons
#+BEGIN_SRC graphviz-dot :file /tmp/cons.svg :cmdline -Kdot -Tsvg
digraph {
graph [bgcolor=transparent]
fontcolor="gray80"
node [color=gray80 shape="box", fontcolor="gray80"]
edge [color=gray80]
rankdir = "LR"
subgraph cluster_0 {
label="Cell"
color="gray80"
graph [bgcolor=transparent, fontcolor="gray80"]
node [color=gray80 shape="box", fontcolor="gray80"]
a0[label="car: 'head"]
b0[label="cdr: 'tail"]
}
}
#+END_SRC
#+RESULTS: ep-5-cons
[[file:/tmp/cons.svg]]
#+BEGIN_SRC emacs-lisp
(setq x1 (cons 'head 'tail))
(car x1)
(cdr x1)
'(head . tail)
(cons 2 nil)
(cons 1 x1)
#+END_SRC
#+NAME: ep-5-list
#+BEGIN_SRC graphviz-dot :file /tmp/list.svg :cmdline -Kdot -Tsvg
digraph {
graph [bgcolor=transparent]
fontcolor="gray80"
node [color=gray80 shape="box", fontcolor="gray80"]
edge [color=gray80]
rankdir = "LR"
subgraph cluster_0 {
label="Cell"
color="gray80"
graph [bgcolor=transparent, fontcolor="gray80"]
node [color=gray80 shape="box", fontcolor="gray80"]
a0[label="car: 1"]
b0[label="cdr: "]
}
subgraph cluster_1 {
label="Cell"
color="gray80"
node [color=gray80 shape="box"]
a1[label="car: 2"]
b1[label="cdr: "]
b0 -> a1
}
subgraph cluster_2 {
label="Cell"
color="gray80"
node [color=gray80 shape="box"]
a2[label="car: 3"]
b2[label="cdr: nil"]
b1 -> a2
}
}
#+END_SRC
#+RESULTS: ep-5-list
[[file:/tmp/list.svg]]
#+BEGIN_SRC emacs-lisp
(setq x2 (cons 1 (cons 2 (cons 3 nil))))
(setq x3 (list 1 2 3))
#+END_SRC
** Some useful functions
- add-to-list
#+BEGIN_SRC emacs-lisp
(setq x4 (list 1 2 3 4))
(add-to-list 'x4 3)
(add-to-list 'x4 6)
#+END_SRC
- push & pop
#+BEGIN_SRC emacs-lisp
(setq x5 (list 1 2 3 4))
(push 1 x5)
(pop x5)
#+END_SRC
- member
#+BEGIN_SRC emacs-lisp
(setq x6 (list 'a 'b 1 2))
(member 'z x6)
(member 1 x6)
#+END_SRC
- delete
#+BEGIN_SRC emacs-lisp
(setq x7 (list 1 2 3 4 5))
(delete 3 x7)
x7
#+END_SRC
- remove
#+BEGIN_SRC emacs-lisp
(setq x8 (list 1 2 3 4 5))
(remove 3 x8)
x8
#+END_SRC
- car
- cdr
#+BEGIN_SRC emacs-lisp
(setq x9 (list 1 2 3 4))
(car x9)
(cdr x9)
#+END_SRC
* DONE Episode 6 - Property & Association Lists
CLOSED: [2022-06-13 Mon 10:38]
** I have an idea
- Develop *FG42* on stream
- I'll announce the date and time on:
+ Twitter: @lxsameer
+ Youtube Community (maybe)
** eq vs equal
- ~eq~ checks whether two objects are the same
- ~equal~ checks whether two objects have similar structure and content.
** Property List (plist)
- Is a list of paired elements
- Each of the pairs associates a property name with a property or value
- The order of the property names (keys) is not significant
- Keys must be unique
- Emacs uses plists to store text properties and symbol properties
*** Examples
#+BEGIN_SRC emacs-lisp
(setq x '(:a 1 "b" 2 c 3 :d ("foo" "bar") :j nil))
x
#+END_SRC
*** Functions
- ~plist-get~ or ~lax-plist-get~
#+BEGIN_SRC emacs-lisp
(plist-get x :a)
(plist-get x "b")
(lax-plist-get x "b")
#+END_SRC
- ~plist-put~ or ~lax-plist-put~
#+BEGIN_SRC emacs-lisp
(plist-put x :z 325)
(plist-put x :z 10)
(lax-plist-put x "b" 20)
#+END_SRC
- ~plist-member~
#+BEGIN_SRC emacs-lisp
(plist-get x :j)
(plist-get x :g)
(plist-member x :j)
(plist-member x :g)
#+END_SRC
** An example use case of plist
#+BEGIN_SRC emacs-lisp
(defun foo (&rest args)
(message "ARGS: %s" args)
(plist-get args :name))
(foo :age 20 :name 'bob "blah" '(12 34 4))
#+END_SRC
** Association List (alist)
- It is a list of cons cells called associations
- Mapping some keys to some values
- The ~CAR~ of each cons cell is the key, and the ~CDR~ is the associated value
- The order of associations matters
*** Examples
#+BEGIN_SRC emacs-lisp
(setq y '((:a . 1) ("b" . 2) (c . 3) (:d "foo" "bar")))
y
#+END_SRC
*** Functions
- ~assoc~
#+BEGIN_SRC emacs-lisp
(assoc :a y)
(assoc "b" y)
#+END_SRC
- ~rassoc~
#+BEGIN_SRC emacs-lisp
(rassoc 1 y)
(rassoc 3 y)
#+END_SRC
- ~assq~
#+BEGIN_SRC emacs-lisp
(assq :a y)
(assq "b" y)
#+END_SRC
- ~alist-get~
#+BEGIN_SRC emacs-lisp
(alist-get :a y)
(alist-get :z y "blah")
#+END_SRC
- ~cons~
#+BEGIN_SRC emacs-lisp
(setq y1 (cons '(:z . 31) y))
(assoc :z y1)
#+END_SRC
** References
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Association-Lists.html
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Plist-Access.html
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Plists-and-Alists.html
* DONE Episode 7 - Basic Loops
CLOSED: [2022-07-09 Sat 10:31]
** About previous episode
- Duplicate keys in an association list
- ~eval-defun~
** While
- Form:
#+BEGIN_SRC emacs-lisp
(while CONDITION
...body...)
#+END_SRC
- Loops and evaluates ~body~ as long as the ~CONDITION~ evaluates to true.
- It always evaluats to the value of the ~CONDITION~ which will be false aaaaall the time.
- We need to explicitly manage the condition.
- Example:
#+BEGIN_SRC emacs-lisp
(let ((foo 1))
(while (< foo 10)
(message ">> %s" foo)
(setq foo (+ 1 foo))))
(let ((foo '(bar baz)))
(while foo
(message ">> %s" (car foo))
(setq foo (cdr foo))))
#+END_SRC
** dolist
- It's a macro
- Form:
#+BEGIN_SRC emacs-lisp
(dolist (element list [result])
...body...)
#+END_SRC
- Evaluates the ~body~ with ~element~ set to the CAR of ~list~ on each iteration
- At the ends evaluates ~result~ and return the evaluation result (if ~result~ is provided)
- Example:
#+BEGIN_SRC emacs-lisp
(let ((foo '(9 8 7 6 5 4)))
(dolist (x foo (+ 10 1))
(message ">> %s" x)))
(let ((foo '(9 8 7 6 5 4)))
(macroexpand-1
'(dolist (x foo 10)
(message ">> %s" x))))
#+END_SRC
** dotimes
- It's a macro too
- Form:
#+BEGIN_SRC emacs-lisp
(dotimes (var number)
...body...)
#+END_SRC
- It's similar to ~dolist~ but iterates ~number~ of times
- ~var~ in will contains the number of current iteration
- Example:
#+BEGIN_SRC emacs-lisp
(let ((foo 10))
(dotimes (x foo)
(message ">> %s" x)))
(let ((foo 10))
(macroexpand-1
'(dotimes (x foo)
(message ">> %s" x))))
#+END_SRC
* DONE Episode 8 - More Loops
CLOSED: [2022-07-29 Fri 15:11]
** Recursion
- A *Recursive* function, is a function that defines in terms of itself
- Easy to implement
- But should be careful with it to aviod infinit loops
*** Example
#+BEGIN_SRC emacs-lisp
(defun foo (int)
(print int)
(when (> int 0)
(foo (- int 1))))
(foo 10)
#+END_SRC
** Functional style loops
*** Mapping functions Family
- ~mapcar~
#+BEGIN_SRC emacs-lisp
(mapcar #'1+ '(1 2 3 4 5))
(mapcar (lambda (x) (* x x))
'(1 2 3 4))
#+END_SRC
- ~mapc~
#+BEGIN_SRC emacs-lisp
(mapc #'1+ '(1 2 3 4 5))
(mapc #'print '(1 2 3 4 5))
#+END_SRC
- ~map-concat~
#+BEGIN_SRC emacs-lisp
(mapconcat (lambda (x)
(format "[%s]" x))
'(1 2 3 4 5)
" <|> ")
#+END_SRC
*** Seq module
A collection of handy functions that operate on ~sequences~.
- ~seq-reduce~
#+BEGIN_SRC emacs-lisp
(require 'seq)
(seq-reduce
(lambda (acc x)
(+ acc x))
'(1 2 3 4)
0)
#+END_SRC
- ~seq-filter~
#+BEGIN_SRC emacs-lisp
(seq-filter (lambda (x) (< x 10))
'(8 12 22 9))
#+END_SRC
- ~seq-partition~
#+BEGIN_SRC emacs-lisp
(seq-partition '(a b c d e f) 2)
#+END_SRC
- ~seq-min~, ~seq-max~
* DONE Episode 9 - Introduction to Macros
CLOSED: [2022-09-11 Sun 11:08]
** What is a macro?
- A macro is defined much like a function
- It works on compile time
- It returns a new expression as the return value
- The compiler "expands" a macro by replacing the macro call with the return value of the macro
- Different evaluation rule than functions
+ Unlike function calls, the arguments to a macro will be passed to the macro as they are,
without evaluation.
- Macros vs inline functions
** How to define and expand a macro?
- We can define a macro using ~defmacro~ form
#+BEGIN_SRC emacs-lisp
(defmacro inc (val)
(list #'1+ val))
(defmacro mydef (name val)
(list 'setq (intern (concat "my-" (symbol-name name))) val))
(defmacro foo (val)
(1+ val))
#+END_SRC
- We can inspect the expansion process using the ~macroexpand~ function family.
+ ~macroexpand~: Expands the macros until no macro exists in the top level forms
+ ~macroexpand-all~: Expands the macros all the way down to the subforms
+ ~macroexpand-1~: Expands the macro only for one level or cycle
#+BEGIN_SRC emacs-lisp
(macroexpand-1 '(inc 10))
(macroexpand-1 '(mydef blah 20))
(print (macroexpand-1 '(when (> 10 5) (print "something"))))
#+END_SRC
** Feedback or question
- https://lxsameer.com
- [[https://twitter.com/lxsameer][@lxsameer]] on Twitter
* DONE Episode 10 - More on Macros
CLOSED: [2022-11-04 Fri 15:25]
** Quasiquote aka backquote (`)
- Backquote constructs allow us to quote an expression, but selectively evaluate sub-expressions
- Similar to a template engine for lisp expressions
- It can be used on its own but it will shine in macro definitions
- On the simplest form it is identical to ~quote~
- Special markers ~,~ and ~,@~ can be used to mark expressions for evaluation
- ~,~ will replace the return value of the evaluation with the expression
- ~,@~ will replace and splice the return value of the evaluation
*** Examples
#+BEGIN_SRC emacs-lisp
`3
`(1 2 3 4)
`(1 2 3 ,(+ 5 6))
`(1 2 3 ,(list 4 5 6))
`(1 2 3 ,@(list 4 5 6))
`(setq ,(intern (upcase "some_var")) 3)
#+END_SRC
** ~declare~ form
- It's a special macro which can be used to add meta properties to a function or macro
+ ~doc-string~
+ ~indent~
** Real Examples
Let's discuss ~defflag~ and ~when-flag~ macros in [[file:../core/fg42/flags.el]]
* DONE Episode 11 - Common pitfalls of Macros
CLOSED: [2022-12-04 Sun 12:15]
** Compiletime vs runtime
#+BEGIN_SRC emacs-lisp
;; `do-something-with-side-effect' evaluates on compile time
;; in the macro's context
(defmacro wrong (x)
(when x
(do-something-with-side-effect x)))
;; `do-something-with-side-effect' evaluates on run time
;; in the caller's context
(defmacro correct (x)
(when x
`(do-something-with-side-effect ,x)))
#+END_SRC
** Variable Capture
#+BEGIN_SRC emacs-lisp
;; `result' will hide any binding with the same name in the
;; parent scope
(defmacro wrong (f &rest body)
`(let ((result ,f))
(if result
,@body
(message "Failed: %s" result))))
(defvar result 1)
(wrong 200 (message "> %s" result))
;; Instead we need to generate a local binding
(defmacro correct (f &rest body)
(let ((var (gensym)))
`(let ((,var ,f))
(if ,var
,@body
(message "Failed: %s" ,var)))))
(defvar result 1)
(correct 200 (message "%s" result))
#+END_SRC
More on *uninterned* symbols: https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html
** Many evaluation
#+BEGIN_SRC emacs-lisp
;; The argument `x' will be evaluated 2 times in this example.
;; what if it contains side effects?
(defmacro wrong (x)
`(if ,x
(do-something-with ,x)
(do-somthing-else ,x)))
;; It's better to use a local binding for it and evaluate it
;; just once
(defmacro correct (x)
(let ((var (gensym)))
`(let ((,var ,x))
(if ,var
(do-something-with ,var)
(do-somthing-else ,var)))))
#+END_SRC
** Evaluating arguments of a macro
Never evaluate the arguments of a macro manually. E.g. with =eval=
#+BEGIN_SRC emacs-lisp
;; `eval' here will be evaluated before the caller context
;; is even populated
(defmacro wrong (x)
(list 'setq (eval x) 'blah))
;; The correct way is to mark `x' for evaluation instead
(defmacro correct (x)
`(setq ,x 'blah))
#+END_SRC
More info: https://www.gnu.org/software/emacs/manual/html_node/elisp/Eval-During-Expansion.html
** What's next?
* DONE Episode 12 - Features & Load Paths
CLOSED: [2023-01-14 Sat 11:44]
** Emacs Lisp files
Write elisp code in files with =.el= suffix.
*** Batch mode
Execute an elisp file via Emacs in a non-interactive (script like) fashion:
#+BEGIN_SRC bash
emacs --batch -l /path/to/the/file
#+END_SRC
*** =load= function
Loads an elisp file into the running Emacs process. For more info ~C-h f load~.
#+BEGIN_SRC emacs-lisp
(load "/path/to/the/file")
(load "PATH1")
#+END_SRC
- It first looks for the =PATH + .elc= combination
- If not successful, looks for the =PATH + .el= combination
- If not successful, looks for platform dependent suffixes
- If not successful, tries to load the =PATH= as it is
** Load Path
*** =load-path=
List of directories to search for files to load.
#+BEGIN_SRC emacs-lisp
(add-to-list 'load-path "/path/to/a/directory")
#+END_SRC
*** =EMACSLOADPATH= environment variable
** Emacs =feature=
Emacs tracks loaded packages and file via =features=. Each elisp file can =provide=, zero or
more =features=.
Features are just symbols.
*** =features= list
A list of all loaded features. For more info, try ~C-h v features~.
*** =featurep=
A predicate function to check whether a feature is loaded or not.
#+BEGIN_SRC emacs-lisp
(featurep 'some-feature)
#+END_SRC
*** =provide=
#+BEGIN_SRC emacs-lisp
(provide 'some-feature)
#+END_SRC
*** =require=
If the given feature as the parameter is not loaded yet, loads it via the =load=
function. For more info, ~C-h f require~.
#+BEGIN_SRC emacs-lisp
(require 'some-feature)
;; Or
(require 'some-feature "/path/to/file")
#+END_SRC
** Installing Emacs packages the hard way
We can clone a library somewhere on the disk and add the path to it to the =load-path= list
and load the library files.
But that would be tedious to do so for all the libraries. That's why we use a package manager
* DONE Episode 13 - Editing Modes, Part 1
CLOSED: [2023-06-10 Sat 15:44]
Emacs provides a concept called ~editing mode~ that allows
us to control different aspect of the editor.
** Major Modes
Major modes are mutually exclusive, so each Buffer has exactly on
major mode and just one major mode can be active at any given
time. So, it is possible to switch between different major modes.
Major modes control the main behaviour of your editor for each buffer.
For example, The active major mode might:
- Provide syntax highlighter
- Control the indentation
- Provide a local =keymap=
- ...
To put it simply, major modes are specialized to handle certain files
and buffers.
*** Naming Convenstion
Usually, the name of a major mode is like =<major-mode-name>-mode= which is
an interactive function that we can call either directly or via =M-x= interface.
For example:
- python-mode
- fundamental-mode
- emacs-lisp-mode
- ...
**** Keymap
*We will take about Keymaps in the future*
Major modes usually have a keymap to hold their local keybindings that has the
the =-map= suffix.
**** Hooks
*We will take about Hooks in the future*
Hooks are lists of functions that can be called on certain occasions. For example,
after a major mode activates.
Usually major modes come with at least one hook called =<major-mode-name>-hook= that
runs after the major mode activates. E.g. =emacs-lisp-mode-hook= or =python-mode-hook=.
*** How Emacs choose a major mode for a buffer?
When we open a file, Emacs goes through some hoops to figure out what major mode
should it choose for that buffer.
To put it simply and avoid a lot of details, Emacs will try to match the buffer name
against the keys in ~auto-mode-alist~ and uses the mode provided by that key as a value.
#+BEGIN_SRC emacs-lisp
(("\\`/tmp/fol/" . text-mode)
("\\.texinfo\\'" . texinfo-mode)
("\\.texi\\'" . texinfo-mode)
("\\.el\\'" . emacs-lisp-mode)
("\\.c\\'" . c-mode)
("\\.h\\'" . c-mode)
…)
#+END_SRC
For more info check out:
https://www.gnu.org/software/emacs/manual/html_node/elisp/Auto-Major-Mode.html
*** How to switch the major mode
Just call the other mode or
- ~major-mode-suspend~: Kills all the buffer local variables and record them
- ~major-mode-restore~: This function restores the major mode recorded by ~major-mode-suspend~
For more info:
https://www.gnu.org/software/emacs/manual/html_node/elisp/Major-Modes.html
** Minor Modes
A minor mode provides optional features that users may enable or disable independently of
the choice of major mode. Minor modes can be enabled individually or in combination.
The main difference with major modes is that minor modes are not mutually exclusive and
are not tied to buffers. They can operate globally or local to buffers.
*** How to enable/disable minor modes?
In order to toggle a minor mode we just have to call its function with no argument
*interactively*. In order to disable a minor mode we can pass a negative integer,
and to enable it we can pass a positive integer.
#+BEGIN_SRC emacs-lisp
;; Enable
(blah-mode 1)
;; Disable
(blah-mode -1)
#+END_SRC
** Useful functions and variables
- ~describe-mode~: Display documentation of current major mode and minor modes and a brief
summary of the state of the current buffer.
- ~local-minor-modes~: This buffer-local variable lists the currently enabled minor modes
in the current buffer, and is a list of symbols.
- ~global-minor-modes~: This variable lists the currently enabled global minor modes,
and is a list of symbols.
- ~minor-mode-list~: The value of this variable is a list of all minor mode commands.
* Episode 14 - Editing Modes, Part 2
** Quick overview:
*** A simple minor mode
*** Interactive functions
*** Hooks
*** Keymaps
** Let's do it
** Resources:
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Library-Headers
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Hooks.html
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Keymaps.html

52
fbt/fbt/build.el Normal file
View File

@ -0,0 +1,52 @@
;;; FGBuildTool --- The build tool for FG42
;;
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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 'fbt/utils)
(require 'fbt/compile)
(defun fbt-build/-clean (dir)
"Clean up all the elc files from the given DIR."
(let ((elcs (elc-files-in dir)))
(when elcs
(message
(shell-command-to-string
(format "rm -v %s" (apply #'concat
(mapcar (lambda (x) (format " %s" x)) elcs))))))))
(defun fbt-build/clean (dirs)
"Clean the given DIRS from elc files."
(mapc #'fbt-build/-clean dirs))
(defun fbt-build/build (&rest params)
"Compile the core and install the dependencies with the given PARAMS."
(fbt-compile/compile "core"))
(provide 'fbt/build)
;;; build.el ends here

41
fbt/fbt/compile.el Normal file
View File

@ -0,0 +1,41 @@
;;; FGBuildTool --- The build tool for FG42
;;
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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 'fbt/utils)
(defun fbt-compile/compile (dir)
"Compile all the elisp files in the given DIR regardless of timestamp.
The DIR should be relative to FG42_HOME."
(let ((target (->path dir)))
(message "Compiling '%s'..." target)
(add-to-list 'load-path target)
(message "Load path:\n%s\n" (apply #'concat (mapcar (lambda (x) (format "%s\n" x)) load-path)))
(byte-recompile-directory target 0 t)))
(provide 'fbt/compile)
;;; compile.el ends here

150
fbt/fbt/fpkg.el Normal file
View File

@ -0,0 +1,150 @@
;;; FGBuildTool --- The build tool for FG42
;;
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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/system/core)
(require 'fg42/system/api)
(defvar bootstrap-version nil
"`straight.el' bootstrap version. Set it in the `system' level, not here.")
(defvar straight-base-dir)
(defvar straight-repository-branch)
(defvar straight-cache-autoloads)
(defvar straight-check-for-modifications)
(defvar straight-enable-package-integration)
(defvar straight-vc-git-default-clone-depth)
(defvar autoload-compute-prefixes)
(defvar straight-fix-org)
(defvar straight-recipe-repositories)
(defvar straight-recipe-overrides)
(defun fbt-fpkg/-set-straight-values (system)
"Set the default values for some of `straight.el' vars for the SYSTEM."
(setq straight-base-dir (fg42-system/fpkg-path system)
straight-repository-branch "develop"
;; Our autoload process is different.
straight-cache-autoloads nil
;; `straight.el' suppose to be a functional pkg manager but it actually
;; allows user to edit libraries in place which we don't like it.
;; We have our own mechanism to allow users extend FG42 so we don't
;; want `straight.el' to handle it. Frankly it reduces the boot time
;; by a lot.
straight-check-for-modifications nil
straight-enable-package-integration nil
;; We don't want `straight.el' to deep clone the dependencies. Some packages
;; might break this way according to `doom-emacs'
straight-vc-git-default-clone-depth 1
;; We have our own autoload system.
autoload-compute-prefixes nil
straight-fix-org nil))
(defun fbt-fpkg/-install-core-dependencies (system)
"Install the core dependencies of the given SYSTEM.
Core dependencies are thoses packages that the system itself is depends on
and not the extensions."
(mapc #'straight-use-recipes (fg42-system/core-dependencies system)))
(defun fbt-fpkg/initialize (system)
"Initilize the package manager for the given SYSTEM.
Basically fpkg will bootstrap and `straight.el' repositoryu for the given
SYSTEM by fetching the required values from it. Including the path to the
target directory."
(unless (fboundp 'straight--reset-caches)
(let ((bootstrap-file (concat (fg42-system/fpkg-path system)
"straight/repos/straight.el/bootstrap.el"))
(bootstrap-version (fg42-system/fpkg-backend-version system)))
(make-directory (fg42-system/fpkg-path system) t)
(fbt-fpkg/-set-straight-values system)
(or (require 'straight nil t)
(file-readable-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
(format "https://raw.githubusercontent.com/raxod502/straight.el/%s/install.el"
straight-repository-branch)
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp))
(load bootstrap-file nil t)))
(require 'straight))
(straight--reset-caches)
(fbt-fpkg/-install-core-dependencies system)
(setq straight-recipe-repositories nil
straight-recipe-overrides nil)
;; Someday we might have to use our own fork of `straight.el'
(straight-register-package
`(straight :type git :host github
:repo "raxod502/straight.el"
:files ("straight*.el")
:branch ,straight-repository-branch
:no-byte-compile t))
(fg42-system/fpkg-initilized! system))
(defun fbt-fpkg/initialize-once (system)
"Initilize FPKG only once for the given SYSTEM."
(when (not (fg42-system/fpkg-initilized-p system))
(fbt-fpkg/initialize system)
;; TODO: Install `use-package'
;; (straight-use-package 'use-package)
))
(defun fbt-fpkg/init (system params)
"Setup fpkg repository with the given PARAMS for the given SYSTEM."
(fbt-fpkg/initialize-once system))
(defun fbt-fpkg/print-help (command)
"Print the usage for fpkg and the possible wrong COMMAND."
(message "Usage:\n")
(message "init - Setup the fpkg repository"))
(defun fbt-fpkg (system params)
"The main interface to `fpkg' subcommand and PARAMS for the loaded SYSTEM."
(let ((subcommand (car args))
(args (cdr params)))
(cond
((string= subcommand "init") (funcall #'fbt-fpkg/init system args))
(t (fbt-fpkg/print-help subcommand)))))
(defun fpt-fpkg/initialize-load-path (system)
"Setup the required load paths from the given SYSTEM."
(add-to-list 'load-path
(path-join (fg42-system/fpkg-path system)
"straight/repos/straight.el/")))
(provide 'fbt/fpkg)
;;; fpkg.el ends here

42
fbt/fbt/lint.el Normal file
View File

@ -0,0 +1,42 @@
;;; FGBuildTool --- The build tool for FG42
;;
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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 'fbt/utils)
(defun lint (dir)
"Run linter on all the elisp files in the given DIR."
(let ((files (el-files-in dir)))
(if files
(dolist (file files)
;; TODO: Setup flycheck here and use it to lint the elisp file.
;; tried to use flymake but it doesn't let you do it manually
(with-temp-buffer
(insert-file-contents file)))
(error "Couldn't find any elisp files"))))
(provide 'fbt/lint)
;;; lint.el ends here

57
fbt/fbt/utils.el Normal file
View File

@ -0,0 +1,57 @@
;;; FGBuildTool --- The build tool for FG42
;;
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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:
(defun ->path (dir)
"Return the absolute path to the given DIR with respect to FG42_HOME."
(concat (getenv "FG42_HOME") (format "/%s" dir)))
(defun find-files (dir suffix)
"Find all the files with the given SUFFIX in the given DIR."
(split-string (shell-command-to-string
(format "find %s -iname \"*.%s\"" (->path dir) suffix)) "\n" t))
(defun el-files-in (dir)
"Return a list of elisp files in the given DIR."
(find-files dir "el"))
(defun elc-files-in (dir)
"Return a list of elisp files in the given DIR."
(find-files dir "elc"))
;; TODO: Merge this into a unified utils module with the one
;; from `fg42/utils' package
(defun path-join (&rest paths)
"Join the given PATHS."
(apply #'concat
(append
(mapcar #'file-name-as-directory (butlast paths))
(last paths))))
(provide 'fbt/utils)
;;; utils.el ends here

65
fg42-config.el Normal file
View File

@ -0,0 +1,65 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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:
(defvar fg42-v3 (or (getenv "FG42_V3") '()))
(if fg42-v3
(add-to-list 'load-path (concat (getenv "FG42_HOME") "/core"))
(add-to-list 'load-path (concat (getenv "FG42_HOME") "/lib")))
;; Prevent package.el to install anything at startup
(setq package-enable-at-startup nil)
(setq tab-width 2)
(setq custom-file (format "%s/.fg42.custom.el" (getenv "HOME")))
(setq user-emacs-directory "~/.fg42/emacs.d")
(setq user-init-file
(format "%s/.fg42.%s"
(getenv "HOME")
(if fg42-v3 "v3.el" "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))
(require 'fg42)
(if (not fg42-v3)
(progn
(load-user-config user-init-file)
(fg42-initialize))
(progn
(fg42/before-initialize)
(fg42/initialize)))
(provide 'fg42-config)
;;; fg42-config.el ends here

4
fg42.app Executable file
View File

@ -0,0 +1,4 @@
#! /bin/sh
#export FG42_HOME=/Users/sameer.rahmani/.fg42
#open -a emacs --args ' --no-splash --title FG42 -l $FG42_HOME/fg42-config.el "$@"'
do shell script "/usr/bin/emacs --name FG42 --no-splash --title FG42 -l /Users/sameer.rahmani/.fg42/fg42-config.el"

View File

@ -1,305 +0,0 @@
{
"nodes": {
"emacs-overlay": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1707815184,
"narHash": "sha256-WFoDXgaPdhjgQB3ut+ZN+VT7e60Yw+KUyvUkOSu5Wto=",
"owner": "nix-community",
"repo": "emacs-overlay",
"rev": "0f7f3b39157419f3035a2dad39fbaf8a4ba0448d",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "emacs-overlay",
"rev": "0f7f3b39157419f3035a2dad39fbaf8a4ba0448d",
"type": "github"
}
},
"emacs-overlay_2": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_3",
"nixpkgs-stable": "nixpkgs-stable_2"
},
"locked": {
"lastModified": 1707815184,
"narHash": "sha256-WFoDXgaPdhjgQB3ut+ZN+VT7e60Yw+KUyvUkOSu5Wto=",
"owner": "nix-community",
"repo": "emacs-overlay",
"rev": "0f7f3b39157419f3035a2dad39fbaf8a4ba0448d",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "emacs-overlay",
"rev": "0f7f3b39157419f3035a2dad39fbaf8a4ba0448d",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1714641030,
"narHash": "sha256-yzcRNDoyVP7+SCNX0wmuDju1NUCt8Dz9+lyUXEI0dbI=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "e5d10a24b66c3ea8f150e47dfdb0416ab7c3390e",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib_2"
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1707689078,
"narHash": "sha256-UUGmRa84ZJHpGZ1WZEBEUOzaPOWG8LZ0yPg1pdDF/yM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f9d39fb9aff0efee4a3d5f4a6d7c17701d38a1d8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1714640452,
"narHash": "sha256-QBx10+k6JWz6u7VsohfSw8g8hjdBZEf8CFzXH1/1Z94=",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/50eb7ecf4cd0a5756d7275c8ba36790e5bd53e33.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/50eb7ecf4cd0a5756d7275c8ba36790e5bd53e33.tar.gz"
}
},
"nixpkgs-lib_2": {
"locked": {
"dir": "lib",
"lastModified": 1711703276,
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
"type": "github"
},
"original": {
"dir": "lib",
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1707650010,
"narHash": "sha256-dOhphIA4MGrH4ElNCy/OlwmN24MsnEqFjRR6+RY7jZw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "809cca784b9f72a5ad4b991e0e7bcf8890f9c3a6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_2": {
"locked": {
"lastModified": 1707650010,
"narHash": "sha256-dOhphIA4MGrH4ElNCy/OlwmN24MsnEqFjRR6+RY7jZw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "809cca784b9f72a5ad4b991e0e7bcf8890f9c3a6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1707451808,
"narHash": "sha256-UwDBUNHNRsYKFJzyTMVMTF5qS4xeJlWoeyJf+6vvamU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "442d407992384ed9c0e6d352de75b69079904e4e",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "442d407992384ed9c0e6d352de75b69079904e4e",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1707689078,
"narHash": "sha256-UUGmRa84ZJHpGZ1WZEBEUOzaPOWG8LZ0yPg1pdDF/yM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f9d39fb9aff0efee4a3d5f4a6d7c17701d38a1d8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1707451808,
"narHash": "sha256-UwDBUNHNRsYKFJzyTMVMTF5qS4xeJlWoeyJf+6vvamU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "442d407992384ed9c0e6d352de75b69079904e4e",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "442d407992384ed9c0e6d352de75b69079904e4e",
"type": "github"
}
},
"noether": {
"inputs": {
"emacs-overlay": "emacs-overlay_2",
"flake-parts": "flake-parts_2",
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1714648678,
"narHash": "sha256-CxLSUYRk2quey0skgxa+v8mVE+pGSSPcxtK0uFq6YkQ=",
"ref": "refs/tags/v0.1.11",
"rev": "b4e667a73a0de7d83f78910d6fa3acc3b3044675",
"revCount": 53,
"type": "git",
"url": "https://devheroes.codes/lxsameer/noether"
},
"original": {
"ref": "refs/tags/v0.1.11",
"type": "git",
"url": "https://devheroes.codes/lxsameer/noether"
}
},
"root": {
"inputs": {
"emacs-overlay": "emacs-overlay",
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs_2",
"noether": "noether"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

100
flake.nix
View File

@ -1,100 +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/>.
{
description = "FG42 - Emacs Editor for advance users";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/442d407992384ed9c0e6d352de75b69079904e4e";
inputs.noether.url = "git+https://devheroes.codes/lxsameer/noether?ref=refs/tags/v0.1.11";
inputs.emacs-overlay.url = "github:nix-community/emacs-overlay/0f7f3b39157419f3035a2dad39fbaf8a4ba0448d";
inputs.flake-parts.url = "github:hercules-ci/flake-parts";
outputs = { self, nixpkgs, flake-parts, ... }@inputs: flake-parts.lib.mkFlake { inherit inputs; } {
systems = [
"aarch64-darwin"
"riscv64-linux"
"x86_64-linux"
];
flake = {
# The home-manager integration. The can use FG42 with home-manager by including
# this module.
hm-module = rec {
fg42 = import ./nix/hm;
default = fg42;
};
};
perSystem = { config, self', inputs', pkgs, system, ... }:
let
test-x = pkgs.writeShellApplication {
name = "test-x";
runtimeInputs = [ pkgs.xorg.xorgserver ];
text = ''
${pkgs.xorg.xorgserver.out}/bin/Xephyr -br -ac -noreset -screen 800x600 :1
'';
};
app = pkgs.callPackage ./nix/fg42 {
inherit nixpkgs;
extraPackages = {
noether = inputs.noether.outputs.packages.${system}.default;
};
};
fg42 = app.drv;
run-test-wm = pkgs.writeShellApplication {
name = "run-test-wm";
runtimeInputs = [ fg42 ];
text = ''
DISPLAY=:1 ${fg42}/bin/fg42-wm
'';
};
in
{
packages = app.emacsPkgs // {
default = fg42;
wm = fg42;
};
devShells.default = pkgs.mkShell {
nativeBuildInputs = [ fg42 pkgs.fish test-x run-test-wm ];
buildInputs = [ fg42 ];
};
apps.wm = {
type = "app";
program = "${run-test-wm}/bin/run-test-wm";
};
apps.x = {
type = "app";
program = "${test-x}/bin/test-x";
};
apps.default = {
type = "app";
program = "${fg42}/bin/fg42";
};
};
};
}

30
lib/extensions/arduino.el Normal file
View File

@ -0,0 +1,30 @@
;; Important Note: On linux you need to add your user to 'dialout' group
;; OS reqyurements: You need to install these utilities:
;; * arduino-mk
;; * python-serial
;; * avrdude
;; * libdevice-serialport-perl
;; * libyaml-perl
;;
;; You need following environments veriables:
;; export ARDUINO_DIR=$HOME/bin/arduino-1.6.8
;; export ARDMK_DIR=/usr/share/arduino
;; export ARDMK_PATH=/usr/bin
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/arduino/init)
;; Dependencies ----------------------------------
(depends-on 'arduino-mode)
(depends-on 'company-arduino)
(depends-on 'mustache)
;; Extension -------------------------------------
(extension arduino
:version "2.31"
:on-initialize extensions/arduino-initialize)
(provide 'extensions/arduino)
;;; arduino.el ends here

View File

@ -0,0 +1,10 @@
# If you didn't define these environment variables, uncomment these and fix the paths
#ARDUINO_DIR=$HOME/bin/arduino-1.6.8
#ARDMK_DIR=/usr/share/arduino
#ARDMK_PATH=/usr/bin
BOARD_TAG=uno
ARDUINO_PORT=/dev/ttyACM0
ARDUINO_LIBS=
include $(ARDMK_DIR)/Arduino.mk

View File

@ -0,0 +1,67 @@
;;; Code:
;; Functions -------------------------------------------------
;;;###autoload
(defun create-makefile ()
"Create the arduino make file in the same directory as the ino file if doesn't exits."
(let ((makefile (concat (file-name-directory buffer-file-name) "Makefile"))
(makefile-src (concat fg42-home "/lib/extensions/arduino/Makefile")))
(if (not (file-exists-p makefile))
(progn (message "Creating arduino make file")
(copy-file makefile-src makefile)))))
;;;###autoload
(defun arduino/compilation-finished (buffer result)
(cond ((string-match "finished" result)
(bury-buffer "*compilation*")
(message "Compilation done."))
(t
(message "Compilation field."))))
;;;###autoload
(defun arduino/compilation-and-upload-finished (buffer result)
(cond ((string-match "finished" result)
(bury-buffer "*compilation*")
(message "Compilation done.")
(message "Uploading")
(arduino/upload))
(t
(message "Compilation field."))))
;;;###autoload
(defun arduino/compile ()
"Compile the current arduino project."
(interactive)
(let ((compilation-finish-functions 'arduino/compilation-finished))
(recompile)))
(defun arduino/upload ()
(interactive)
(let ((compile-command "make upload"))
(recompile)))
;;;###autoload
(defun arduino/compile-and-upload ()
"Compile and upload the current arduino project."
(interactive)
(let ((compilation-finish-functions 'arduino/compilation-and-upload-finished))
(recompile)))
;;;###autoload
(defun extensions/arduino-initialize ()
"Arduino development plugin initialization."
(ability arduino-editor ('flycheck)
"Gives FG42 the ability to edit arduino related contents."
(add-hook 'arduino-mode-hook 'create-makefile)
(setq auto-mode-alist (cons '("\\.\\(pde\\|ino\\)$" . arduino-mode) auto-mode-alist))
(global-set-key (kbd "C-c c") 'arduino/compile)
(global-set-key (kbd "C-c u") 'arduino/upload)
(autoload 'arduino-mode "arduino-mode" "Arduino editing mode." t))
(message "'arduino' extension has been initialized."))
(provide 'extensions/arduino/init)

22
lib/extensions/auth.el Normal file
View File

@ -0,0 +1,22 @@
;;; Auth --- Secret management extension for FG42
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/auth/init)
;; Dependencies ----------------------------------
(depends-on 'rcauth-notify)
(defun auth-doc ()
"TBD"
"TBD")
;; Extension -------------------------------------
(extension auth
:version "2.32"
:on-initialize extensions/auth-initialize
:docs "lib/extensions/auth/readme.org")
(provide 'extensions/auth)
;;; auth.el ends here

View File

@ -0,0 +1,45 @@
;;; Auth --- Secret management extension for FG42
;;; Commentary:
;;; Code:
(require 'auth-source)
(defvar auht/sources '((:sources "~/.authinfo.gpg")))
(defun auth/find-credential (host)
"Find the credential for the given HOST.
Return a list of credential pairs."
(let (auth-list '())
(dolist (cred (auth-source-search :host host
:require '(:user :secret)))
(let ((user (plist-get cred :user))
(secret (plist-get cred :secret)))
(add-to-list 'auth-list
(list user
(if (functionp secret)
(funcall secret)
secret)))))
auth-list))
(defun utils/bold (text)
"Make the TEXT appears in bold form."
(propertize text 'face 'bold))
(defun auth/credential-for (args host)
"Return the credential for the given HOST.
ARGS should be ignored."
(interactive "P\nsHost: ")
(dolist (pair (auth/find-credential host))
(let* ((user (car pair))
(pass (car (cdr pair)))
(msg (concat "User: " (utils/bold user)
" Passowrd: " (utils/bold pass))))
(message msg))))
(defun extensions/irc-initialize ()
"Initialize the Auth extension."
(setq auth-sources auth/sources))
(provide 'extensions/irc/init)
;;; init.el ends here

27
lib/extensions/clojure.el Normal file
View File

@ -0,0 +1,27 @@
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/clojure/init)
;; Dependencies ----------------------------------
(depends-on 'clojure-mode)
(depends-on 'cider)
(depends-on 'paredit)
(depends-on 'flycheck)
(depends-on 'flycheck-clojure)
(depends-on 'clj-refactor)
(depends-on 'let-alist)
(depends-on 'clojure-mode-extra-font-locking)
(depends-on 'flycheck-clj-kondo)
;(depends-on 'core-async-mode)
(depends-on 'yesql-ghosts)
(depends-on 'rainbow-delimiters)
(defun clojure-doc ()
"something fun")
;; Extension -------------------------------------
(extension clojure
:version "2.32"
:on-initialize extensions/clojure-initialize
:docs "lib/extensions/clojure/readme.org")
(provide 'extensions/clojure)

View File

@ -0,0 +1,320 @@
(defun setup-keys ()
(define-key clojure-mode-map (kbd "M-<right>") 'paredit-forward-slurp-sexp)
(define-key clojure-mode-map (kbd "M-<left>") 'paredit-backward-slurp-sexp)
(define-key clojure-mode-map (kbd "C-<right>") 'right-word)
(define-key clojure-mode-map (kbd "C-<left>") 'left-word)
(global-set-key (kbd "C-<right>") 'right-word)
(global-set-key (kbd "C-<left>") 'left-word))
;; Add requires to blank devcards files
(defun cljr--find-source-ns-of-devcard-ns (test-ns test-file)
(let* ((ns-chunks (split-string test-ns "[.]" t))
(test-name (car (last ns-chunks)))
(src-dir-name (s-replace "devcards/" "src/" (file-name-directory test-file)))
(replace-underscore (-partial 's-replace "_" "-"))
(src-ns (car (--filter (or (s-prefix-p it test-name)
(s-suffix-p it test-name))
(-map (lambda (file-name)
(funcall replace-underscore
(file-name-sans-extension file-name)))
(directory-files src-dir-name))))))
(when src-ns
(mapconcat 'identity (append (butlast ns-chunks) (list src-ns)) "."))))
(defun clj--find-devcards-component-name ()
(or
(ignore-errors
(with-current-buffer
(find-file-noselect (clj--src-file-name-from-cards (buffer-file-name)))
(save-excursion
(goto-char (point-max))
(search-backward "defcomponent ")
(clojure-forward-logical-sexp)
(skip-syntax-forward " ")
(let ((beg (point))
(end (progn (re-search-forward "\\w+")
(point))))
(buffer-substring-no-properties beg end)))))
""))
(defun cljr--add-card-declarations ()
(save-excursion
(let* ((ns (clojure-find-ns))
(source-ns (cljr--find-source-ns-of-devcard-ns ns (buffer-file-name))))
(cljr--insert-in-ns ":require")
(when source-ns
(insert "[" source-ns " :refer [" (clj--find-devcards-component-name) "]]"))
(cljr--insert-in-ns ":require")
(insert "[devcards.core :refer-macros [defcard]]"))
(indent-region (point-min) (point-max))))
(defun live-delete-and-extract-sexp ()
"Delete the sexp and return it."
(interactive)
(let* ((begin (point)))
(forward-sexp)
(let* ((result (buffer-substring-no-properties begin (point))))
(delete-region begin (point))
result)))
(defun live-cycle-clj-coll ()
"convert the coll at (point) from (x) -> {x} -> [x] -> (x) recur"
(interactive)
(let* ((original-point (point)))
(while (and (> (point) 1)
(not (equal "(" (buffer-substring-no-properties (point) (+ 1 (point)))))
(not (equal "{" (buffer-substring-no-properties (point) (+ 1 (point)))))
(not (equal "[" (buffer-substring-no-properties (point) (+ 1 (point))))))
(backward-char))
(cond
((equal "(" (buffer-substring-no-properties (point) (+ 1 (point))))
(insert "{" (substring (live-delete-and-extract-sexp) 1 -1) "}"))
((equal "{" (buffer-substring-no-properties (point) (+ 1 (point))))
(insert "[" (substring (live-delete-and-extract-sexp) 1 -1) "]"))
((equal "[" (buffer-substring-no-properties (point) (+ 1 (point))))
(insert "(" (substring (live-delete-and-extract-sexp) 1 -1) ")"))
((equal 1 (point))
(message "beginning of file reached, this was probably a mistake.")))
(goto-char original-point)))
(defun my-toggle-expect-focused ()
(interactive)
(save-excursion
(search-backward "(expect" (cljr--point-after 'cljr--goto-toplevel))
(forward-word)
(if (looking-at "-focused")
(paredit-forward-kill-word)
(insert "-focused"))))
(defun my-remove-all-focused ()
(interactive)
(save-excursion
(goto-char (point-min))
(while (search-forward "(expect-focused" nil t)
(delete-char -8))))
(defun clj-duplicate-top-level-form ()
(interactive)
(save-excursion
(cljr--goto-toplevel)
(insert (cljr--extract-sexp) "\n")
(cljr--just-one-blank-line)))
(defun clj-hippie-expand-no-case-fold ()
(interactive)
(let ((old-syntax (char-to-string (char-syntax ?/))))
(modify-syntax-entry ?/ " ")
(hippie-expand-no-case-fold)
(modify-syntax-entry ?/ old-syntax)))
(defun nrepl-warn-when-not-connected ()
(interactive)
(message "Oops! You're not connected to an nREPL server. Please run M-x cider or M-x cider-jack-in to connect."))
;;;###autoload
(defun cljr-init ()
(interactive)
(require 'clj-refactor)
(clj-refactor-mode 1)
(setq cljr-magic-require-namespaces
'(("io" . "clojure.java.io")
("set" . "clojure.set")
("str" . "clojure.string")
("walk" . "clojure.walk")
("zip" . "clojure.zip")
("time" . "clj-time.core")
("log" . "clojure.tools.logging")
("json" . "cheshire.core")))
;; refer all from expectations
(setq cljr-expectations-test-declaration "[expectations :refer :all]")
;; insert keybinding setup here
(cljr-add-keybindings-with-prefix "C-c v")
(setq cljr-favor-prefix-notation nil)
(setq cljr-favor-private-functions nil)
;; Don't warn me about the dangers of clj-refactor, fire the missiles!
(setq cljr-warn-on-eval nil)
(add-hook 'clojure-mode-hook #'yas-minor-mode)
;; no auto sort
(setq cljr-auto-sort-ns nil)
;; do not prefer prefixes when using clean-ns
(setq cljr-favor-prefix-notation nil)
(cljr-add-keybindings-with-modifier "C-s-")
(define-key clj-refactor-map (kbd "C-x C-r") 'cljr-rename-file)
(define-key clojure-mode-map [remap paredit-forward] 'clojure-forward-logical-sexp)
(define-key clojure-mode-map [remap paredit-backward] 'clojure-backward-logical-sexp)
(define-key clojure-mode-map (kbd "C->") 'cljr-thread)
(define-key clojure-mode-map (kbd "C-<") 'cljr-unwind)
(define-key clj-refactor-map
(cljr--key-pairs-with-modifier "C-s-" "xf") 'my-toggle-expect-focused)
(define-key clj-refactor-map
(cljr--key-pairs-with-modifier "C-s-" "xr") 'my-remove-all-focused)
(defadvice cljr--add-ns-if-blank-clj-file (around add-devcards activate)
(ignore-errors
(when (and cljr-add-ns-to-blank-clj-files
(cljr--clojure-ish-filename-p (buffer-file-name))
(= (point-min) (point-max)))
ad-do-it
(when (clj--is-card? (buffer-file-name))
(cljr--add-card-declarations)))))
(defadvice cljr-find-usages (before setup-grep activate)
(window-configuration-to-register ?$)))
;;;###autoload
(defun clojure-mode-init ()
(interactive)
(require 'clojure-mode-extra-font-locking)
(require 'cider)
(require 'paredit)
;; indent [quiescent.dom :as d] specially
(define-clojure-indent
(d/a 1)
(d/button 1)
(d/div 1)
(d/form 1)
(d/h1 1)
(d/h2 1)
(d/h3 1)
(d/h4 1)
(d/h5 1)
(d/hr 1)
(d/img 1)
(d/label 1)
(d/li 1)
(d/option 1)
(d/p 1)
(d/pre 1)
(d/select 1)
(d/small 1)
(d/span 1)
(d/strong 1)
(d/ul 1)
(d/svg 1)
;; Hafslund specifics
(e/prose 1)
(e/value 1)
(e/section 1)
(e/section-prose 1)
(e/page 1)
(e/instructions 1)
(l/padded 1)
(l/bubble-grid 1)
(l/slider 1)
(l/bottom-fixed 1)
(c/box 1)
(c/group 1)
(c/list 1))
(defadvice clojure-test-run-tests (before save-first activate)
(save-buffer))
(defadvice nrepl-load-current-buffer (before save-first activate)
(save-buffer))
(setq cider-pprint-fn 'pprint)
(setq cider-repl-history-file (concat tmp-directory "/cider-repl-history"))
;; nice pretty printing
(setq cider-repl-use-pretty-printing t)
;; nicer font lock in REPL
(setq cider-repl-use-clojure-font-lock t)
;; result prefix for the REPL
(setq cider-repl-result-prefix ";; => ")
;; never ending REPL history
(setq cider-repl-wrap-history t)
;; looong history
(setq cider-repl-history-size 3000)
;; error buffer not popping up
(setq cider-show-error-buffer nil)
;; Use figwheel for cljs repl
(setq cider-cljs-lein-repl "(do (use 'figwheel-sidecar.repl-api) (start-figwheel!) (cljs-repl))")
;; Indent and highlight more commands
(put-clojure-indent 'match 'defun)
;; Hide nrepl buffers when switching buffers (switch to by prefixing with space)
(setq nrepl-hide-special-buffers t)
;; Enable error buffer popping also in the REPL:
(setq cider-repl-popup-stacktraces t)
;; Specify history file
(setq cider-history-file (concat (getenv "HOME") "/.tmp/nrepl-history"))
;; auto-select the error buffer when it's displayed
(setq cider-auto-select-error-buffer t)
;; Prevent the auto-display of the REPL buffer in a separate window after connection is established
(setq cider-repl-pop-to-buffer-on-connect nil)
;; Pretty print results in repl
(setq cider-repl-use-pretty-printing t)
;; Don't prompt for symbols
(setq cider-prompt-for-symbol nil)
;; eldoc for clojure
(add-hook 'cider-repl-mode-hook #'paredit-mode)
(setup-keys)
(rainbow-delimiters-mode)
(define-key clojure-mode-map (kbd "C-`") 'live-cycle-clj-coll)
(define-key cider-repl-mode-map (kbd "<home>") nil)
(define-key cider-repl-mode-map (kbd "C-,") 'complete-symbol)
(define-key cider-mode-map (kbd "C-,") 'complete-symbol)
(define-key cider-mode-map (kbd "C-c C-q") 'nrepl-close)
(define-key cider-mode-map (kbd "C-c C-Q") 'cider-quit)
(define-key clojure-mode-map (kbd "M-s-d") 'clj-duplicate-top-level-form)
(add-to-list 'cljr-project-clean-functions 'cleanup-buffer)
(define-key clojure-mode-map (kbd "s-j") 'clj-jump-to-other-file)
;;(define-key clojure-mode-map (kbd "C-.") 'clj-hippie-expand-no-case-fold)
(define-key clojure-mode-map (kbd "C-M-x") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-x C-e") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-e") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-l") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-r") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-z") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-k") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-n") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-q") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "M-<right>") 'paredit-forward-slurp-sexp)
(define-key clojure-mode-map (kbd "M-<left>") 'paredit-backward-slurp-sexp)
(define-key clojure-mode-map (kbd "C-<right>") 'right-word)
(define-key clojure-mode-map (kbd "C-<left>") 'left-word)
(global-set-key (kbd "C-<right>") 'right-word)
(global-set-key (kbd "C-<left>") 'left-word)
(message "Clojure mode hook ran and initialized clojure-editor ability."))
(provide 'extensions/clojure/core)

View File

@ -0,0 +1,65 @@
(require 'extensions/clojure/core)
;;;###autoload
(defun set-clojure-favorite-buffer ()
"Set the favorite buffer to cider repl"
(setq *favorite-buffer* "\*cider-repl\s.*\*"))
;;;###autoload
(defun clojure-pretty-symbol ()
(interactive)
(setq prettify-symbols-alist
'(
("fn" . 955) ; λ
("->" . 8594)))) ; →
; ⇒
;;;###autoload
(defun extensions/clojure-initialize ()
; Clojure development initialization
(ability clojure-editor ('flycheck)
(require 'clojure-mode)
(require 'flycheck-clj-kondo)
(add-to-list 'auto-mode-alist '("\\.clj$" . clojure-mode))
(add-to-list 'auto-mode-alist '("\\.cljc$" . clojurec-mode))
(add-to-list 'auto-mode-alist '("\\.cljs$" . clojurescript-mode))
(add-hook 'cider-mode-hook #'eldoc-mode)
(add-hook 'cider-mode-hook #'set-clojure-favorite-buffer)
(add-hook 'clojure-mode-hook #'paredit-mode)
(add-hook 'clojure-mode-hook #'rainbow-delimiters-mode)
(setq cider-cljs-lein-repl "(do (use 'figwheel-sidecar.repl-api) (start-figwheel!) (cljs-repl))")
(add-hook 'clojure-mode-hook 'clojure-mode-init)
(setq tmp-directory (concat (getenv "HOME") "/.tmp")))
(ability pretty-symbols ()
(add-hook 'clojure-mode-hook 'clojure-pretty-symbol))
(ability clojure-completion ('code-completion)
;; company mode for completion
(add-hook 'cider-repl-mode-hook #'company-mode)
(add-hook 'cider-mode-hook #'company-mode))
(ability clojure-refactore ()
(add-hook 'clojure-mode-hook 'cljr-init)))
;; (ability clojure-check ('flycheck)
;; (require 'flycheck-clojure)
;; (eval-after-load 'flycheck '(add-to-list 'flycheck-checkers 'clojure-cider-eastwood))
;; (eval-after-load 'flycheck '(flycheck-clojure-setup))
;; (add-hook 'after-init-hook #'global-flycheck-mode)
;; ;; Set up linting of clojure code with eastwood
;; ;; Make sure to add [acyclic/squiggly-clojure "0.1.2-SNAPSHOT"]
;; ;; to your :user :dependencies in .lein/profiles.clj
;; (add-hook 'cider-mode-hook
;; '(lambda ()
;; (message "Make sure to add [acyclic/squiggly-clojure \"0.1.2-SNAPSHOT\"] to your :user :dependencies in .lein/profiles.clj")))))
(provide 'extensions/clojure/init)

View File

@ -0,0 +1,6 @@
* Clojure Extension
This extension provides an integrated environment for developing clojure applications
using FG42 on top of cider.
** Usage

View File

@ -0,0 +1,311 @@
(require 'clojure-mode)
(require 'clojure-mode-extra-font-locking)
(defadvice clojure-test-run-tests (before save-first activate)
(save-buffer))
(defadvice nrepl-load-current-buffer (before save-first activate)
(save-buffer))
(require 'clj-refactor)
(setq cljr-favor-prefix-notation nil)
(setq cljr-favor-private-functions nil)
(cljr-add-keybindings-with-modifier "C-s-")
(define-key clj-refactor-map (kbd "C-x C-r") 'cljr-rename-file)
(define-key clojure-mode-map [remap paredit-forward] 'clojure-forward-logical-sexp)
(define-key clojure-mode-map [remap paredit-backward] 'clojure-backward-logical-sexp)
(setq cider-pprint-fn 'pprint)
(require 'core-async-mode)
(defun enable-clojure-mode-stuff ()
(clj-refactor-mode 1)
(when (not (s-ends-with-p "/dev/user.clj" (buffer-file-name)))
(core-async-mode 1)))
(add-hook 'clojure-mode-hook 'enable-clojure-mode-stuff)
(require 'symbol-focus)
(define-key clojure-mode-map (kbd "M-s-f") 'sf/focus-at-point)
(defun clj-duplicate-top-level-form ()
(interactive)
(save-excursion
(cljr--goto-toplevel)
(insert (cljr--extract-sexp) "\n")
(cljr--just-one-blank-line)))
(define-key clojure-mode-map (kbd "M-s-d") 'clj-duplicate-top-level-form)
(add-to-list 'cljr-project-clean-functions 'cleanup-buffer)
(define-key clojure-mode-map (kbd "C->") 'cljr-thread)
(define-key clojure-mode-map (kbd "C-<") 'cljr-unwind)
(define-key clojure-mode-map (kbd "s-j") 'clj-jump-to-other-file)
(define-key clojure-mode-map (kbd "C-.") 'clj-hippie-expand-no-case-fold)
(defun clj-hippie-expand-no-case-fold ()
(interactive)
(let ((old-syntax (char-to-string (char-syntax ?/))))
(modify-syntax-entry ?/ " ")
(hippie-expand-no-case-fold)
(modify-syntax-entry ?/ old-syntax)))
(require 'cider)
(define-key cider-repl-mode-map (kbd "<home>") nil)
(define-key cider-repl-mode-map (kbd "C-,") 'complete-symbol)
(define-key cider-mode-map (kbd "C-,") 'complete-symbol)
(define-key cider-mode-map (kbd "C-c C-q") 'nrepl-close)
(define-key cider-mode-map (kbd "C-c C-Q") 'cider-quit)
(require 'yesql-ghosts)
;; indent [quiescent.dom :as d] specially
(define-clojure-indent
(d/a 1)
(d/button 1)
(d/div 1)
(d/form 1)
(d/h1 1)
(d/h2 1)
(d/h3 1)
(d/h4 1)
(d/h5 1)
(d/hr 1)
(d/img 1)
(d/label 1)
(d/li 1)
(d/option 1)
(d/p 1)
(d/pre 1)
(d/select 1)
(d/small 1)
(d/span 1)
(d/strong 1)
(d/ul 1)
(d/svg 1)
;; Hafslund specifics
(e/prose 1)
(e/value 1)
(e/section 1)
(e/section-prose 1)
(e/page 1)
(e/instructions 1)
(l/padded 1)
(l/bubble-grid 1)
(l/slider 1)
(l/bottom-fixed 1)
(c/box 1)
(c/group 1)
(c/list 1))
;; Don't warn me about the dangers of clj-refactor, fire the missiles!
(setq cljr-warn-on-eval nil)
;; Use figwheel for cljs repl
(setq cider-cljs-lein-repl "(do (use 'figwheel-sidecar.repl-api) (start-figwheel!) (cljs-repl))")
;; Indent and highlight more commands
(put-clojure-indent 'match 'defun)
;; Hide nrepl buffers when switching buffers (switch to by prefixing with space)
(setq nrepl-hide-special-buffers t)
;; Enable error buffer popping also in the REPL:
(setq cider-repl-popup-stacktraces t)
;; Specify history file
(setq cider-history-file "~/.emacs.d/nrepl-history")
;; auto-select the error buffer when it's displayed
(setq cider-auto-select-error-buffer t)
;; Prevent the auto-display of the REPL buffer in a separate window after connection is established
(setq cider-repl-pop-to-buffer-on-connect nil)
;; Pretty print results in repl
(setq cider-repl-use-pretty-printing t)
;; Don't prompt for symbols
(setq cider-prompt-for-symbol nil)
;; Enable eldoc in Clojure buffers
(add-hook 'cider-mode-hook #'eldoc-mode)
;; Some expectations features
(require 'clj-autotest)
(defun my-toggle-expect-focused ()
(interactive)
(save-excursion
(search-backward "(expect" (cljr--point-after 'cljr--goto-toplevel))
(forward-word)
(if (looking-at "-focused")
(paredit-forward-kill-word)
(insert "-focused"))))
(defun my-remove-all-focused ()
(interactive)
(save-excursion
(goto-char (point-min))
(while (search-forward "(expect-focused" nil t)
(delete-char -8))))
(define-key clj-refactor-map
(cljr--key-pairs-with-modifier "C-s-" "xf") 'my-toggle-expect-focused)
(define-key clj-refactor-map
(cljr--key-pairs-with-modifier "C-s-" "xr") 'my-remove-all-focused)
;; Cycle between () {} []
(defun live-delete-and-extract-sexp ()
"Delete the sexp and return it."
(interactive)
(let* ((begin (point)))
(forward-sexp)
(let* ((result (buffer-substring-no-properties begin (point))))
(delete-region begin (point))
result)))
(defun live-cycle-clj-coll ()
"convert the coll at (point) from (x) -> {x} -> [x] -> (x) recur"
(interactive)
(let* ((original-point (point)))
(while (and (> (point) 1)
(not (equal "(" (buffer-substring-no-properties (point) (+ 1 (point)))))
(not (equal "{" (buffer-substring-no-properties (point) (+ 1 (point)))))
(not (equal "[" (buffer-substring-no-properties (point) (+ 1 (point))))))
(backward-char))
(cond
((equal "(" (buffer-substring-no-properties (point) (+ 1 (point))))
(insert "{" (substring (live-delete-and-extract-sexp) 1 -1) "}"))
((equal "{" (buffer-substring-no-properties (point) (+ 1 (point))))
(insert "[" (substring (live-delete-and-extract-sexp) 1 -1) "]"))
((equal "[" (buffer-substring-no-properties (point) (+ 1 (point))))
(insert "(" (substring (live-delete-and-extract-sexp) 1 -1) ")"))
((equal 1 (point))
(message "beginning of file reached, this was probably a mistake.")))
(goto-char original-point)))
(define-key clojure-mode-map (kbd "C-`") 'live-cycle-clj-coll)
;; Warn about missing nREPL instead of doing stupid things
(defun nrepl-warn-when-not-connected ()
(interactive)
(message "Oops! You're not connected to an nREPL server. Please run M-x cider or M-x cider-jack-in to connect."))
(define-key clojure-mode-map (kbd "C-M-x") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-x C-e") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-e") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-l") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-r") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-z") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-k") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-n") 'nrepl-warn-when-not-connected)
(define-key clojure-mode-map (kbd "C-c C-q") 'nrepl-warn-when-not-connected)
(setq cljr-magic-require-namespaces
'(("io" . "clojure.java.io")
("set" . "clojure.set")
("str" . "clojure.string")
("walk" . "clojure.walk")
("zip" . "clojure.zip")
("time" . "clj-time.core")
("log" . "clojure.tools.logging")
("json" . "cheshire.core")))
;; refer all from expectations
(setq cljr-expectations-test-declaration "[expectations :refer :all]")
;; Add requires to blank devcards files
(defun cljr--find-source-ns-of-devcard-ns (test-ns test-file)
(let* ((ns-chunks (split-string test-ns "[.]" t))
(test-name (car (last ns-chunks)))
(src-dir-name (s-replace "devcards/" "src/" (file-name-directory test-file)))
(replace-underscore (-partial 's-replace "_" "-"))
(src-ns (car (--filter (or (s-prefix-p it test-name)
(s-suffix-p it test-name))
(-map (lambda (file-name)
(funcall replace-underscore
(file-name-sans-extension file-name)))
(directory-files src-dir-name))))))
(when src-ns
(mapconcat 'identity (append (butlast ns-chunks) (list src-ns)) "."))))
(defun clj--find-devcards-component-name ()
(or
(ignore-errors
(with-current-buffer
(find-file-noselect (clj--src-file-name-from-cards (buffer-file-name)))
(save-excursion
(goto-char (point-max))
(search-backward "defcomponent ")
(clojure-forward-logical-sexp)
(skip-syntax-forward " ")
(let ((beg (point))
(end (progn (re-search-forward "\\w+")
(point))))
(buffer-substring-no-properties beg end)))))
""))
(defun cljr--add-card-declarations ()
(save-excursion
(let* ((ns (clojure-find-ns))
(source-ns (cljr--find-source-ns-of-devcard-ns ns (buffer-file-name))))
(cljr--insert-in-ns ":require")
(when source-ns
(insert "[" source-ns " :refer [" (clj--find-devcards-component-name) "]]"))
(cljr--insert-in-ns ":require")
(insert "[devcards.core :refer-macros [defcard]]"))
(indent-region (point-min) (point-max))))
(defadvice cljr--add-ns-if-blank-clj-file (around add-devcards activate)
(ignore-errors
(when (and cljr-add-ns-to-blank-clj-files
(cljr--clojure-ish-filename-p (buffer-file-name))
(= (point-min) (point-max)))
ad-do-it
(when (clj--is-card? (buffer-file-name))
(cljr--add-card-declarations)))))
;; Set up linting of clojure code with eastwood
;; Make sure to add [acyclic/squiggly-clojure "0.1.2-SNAPSHOT"]
;; to your :user :dependencies in .lein/profiles.clj
(require 'flycheck-clojure)
(defun my-cider-mode-enable-flycheck ()
;; (when (and (s-ends-with-p ".clj" (buffer-file-name))
;; (not (s-ends-with-p "/dev/user.clj" (buffer-file-name))))
;; (flycheck-mode 1))
)
(add-hook 'cider-mode-hook 'my-cider-mode-enable-flycheck)
(eval-after-load 'flycheck '(add-to-list 'flycheck-checkers 'clojure-cider-eastwood))
;; Make q quit out of find-usages to previous window config
(defadvice cljr-find-usages (before setup-grep activate)
(window-configuration-to-register ?$))
;; ------------
;; TODO: Loot more stuff from:
;; - https://github.com/overtone/emacs-live/blob/master/packs/dev/clojure-pack/config/paredit-conf.el
(provide 'setup-clojure-mode)

View File

@ -0,0 +1,28 @@
;;; CommonLispExtension --- Enables common lisp development on FG42
;;; Commentary:
;; In order to user racket extension `racket' itself should
;; be available on the path provided by `exec-path'.
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/common-lisp/init)
;; Dependencies ----------------------------------
(depends-on 'paredit)
(depends-on 'flycheck)
(depends-on 'rainbow-delimiters)
(depends-on 'slime)
(depends-on 'slime-company)
(defun common-lisp-doc ()
"TBD")
;; Extension -------------------------------------
(extension common-lisp
:version "2.32"
:on-initialize extensions/common-lisp-initialize
:docs "lib/extensions/common-lisp/readme.org")
(provide 'extensions/common-lisp)
;;; common-lisp.el ends here

View File

@ -0,0 +1,30 @@
;;; common-lisp-init --- The entry point for common lisp extension
;;; Commentary:
;;; Code:
(defvar default-lisp-platform "sbcl"
"The default Lisp compiler/interpreter to be used with common-lisp extension.")
(defvar ql-slime-helper-path "~/quicklisp/slime-helper.el"
"Default path for the slime-helper installed using quicklisp.")
;;;###autoload
(defun extensions/common-lisp-initialize ()
"Initialize the common Lisp extension."
(require 'slime)
(setq inferior-lisp-program default-lisp-platform)
(setq slime-contribs '(slime-fancy))
(slime-setup '(slime-company))
(add-hook 'slime-load-hook
(lambda ()
(define-key slime-prefix-map (kbd "M-h")
'slime-documentation-lookup)))
(let ((ql-slime-helper (expand-file-name ql-slime-helper-path)))
(when (file-exists-p ql-slime-helper)
(load ql-slime-helper))))
(provide 'extensions/common-lisp/init)
;;; init ends here

View File

@ -0,0 +1,82 @@
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/development/init)
;; Dependencies ----------------------------------
(depends-on 'company)
(depends-on 'company-statistics)
(depends-on 'projectile)
(depends-on 'yasnippet)
(depends-on 'yasnippet-snippets)
(depends-on 'smart-mode-line)
(depends-on 'quickrun)
(depends-on 'dash)
(depends-on 'websocket)
(with-ability terraform
(depends-on 'terraform-mode))
(with-ability yaml
(depends-on 'yaml-mode))
;; (with-ability hl
;; (depends-on 'hl-sexp))
(with-ability dumb-jump
(depends-on 'dumb-jump))
(with-ability bookmarks
(depends-on 'bm))
(with-ability git
(depends-on 'diff-hl)
(depends-on 'magit)
(depends-on 'gh)
(when (is-evil?)
(depends-on 'evil-magit)))
(with-ability github
(depends-on 'magithub))
(with-ability focus
(depends-on 'focus))
(with-ability code-browser
(depends-on 'neotree))
(with-ability pt
(depends-on 'pt))
(with-ability spell
(depends-on 'flyspell))
(with-ability file-browser
(depends-on 'ranger))
(with-ability shell
(depends-on 'eshell-prompt-extras)
(depends-on 'shell-pop))
(with-ability imenu
(depends-on 'imenu)
(depends-on 'imenu-list)
(depends-on 'imenu-anywhere))
(with-ability lsp
(depends-on 'lsp-mode)
(depends-on 'lsp-ui)
(depends-on 'company-lsp))
(with-ability dap
(depends-on 'dap-mode))
;; TODO: Add flycheck-color-modebar
;; TODO Add flycheck-tip
;; Extension -------------------------------------
(extension development
:version "2.31"
:on-initialize extension/development-initialize)
(provide 'extensions/development)

View File

@ -0,0 +1,368 @@
;;; development-extension --- A general extension for general development
;;; Commentary:
;;; Code:
;; Functions -------------------------------------------------
;;;###autoload
(defun disable-projectile ()
(interactive)
(projectile-global-mode nil))
;; Quick fix for company-mode and yasnippet clashing
(defun company-yasnippet-or-completion ()
(interactive)
(if (yas/expansion-at-point)
(progn (company-abort)
(yas/expand))
(company-complete-common)))
(defun yas/expansion-at-point ()
"Tested with v0.6.1. Extracted from `yas/expand-1'"
(first (yas/current-key)))
(defun eval-and-replace ()
"Replace the preceding sexp with its value."
(interactive)
(backward-kill-sexp)
(condition-case nil
(prin1 (eval (read (current-kill 0)))
(current-buffer))
(error (message "Invalid expression")
(insert (current-kill 0)))))
;;;###autoload
(defun enable-pt-search ()
(interactive)
(define-key projectile-mode-map (kbd "C-c p s s") 'projectile-pt)
(define-key projectile-mode-map (kbd "C-c p s r") 'pt-regexp))
(defun load-necessary-modes-and-keybindings ()
"Load the modes and keybindings which at necessary and are not part ofcourse an ability."
(which-function-mode))
;;;###autoload
(defun extension/development-initialize ()
"Development plugin initialization."
(load-necessary-modes-and-keybindings)
(ability project-config ()
"Makes projects configurable."
(require 'projects/configuration))
(ability pretty-symbols ()
"Replace some symbols with icons"
(global-prettify-symbols-mode 1))
(ability lsp ()
"LSP integration for FG42"
(require 'lsp-mode)
(require 'lsp-ui-imenu)
;; Disabling inline actions. Accessable via lsp-execute-code-action
(setq lsp-ui-sideline-show-code-actions nil)
(add-hook 'lsp-after-open-hook 'lsp-enable-imenu)
(setq lsp-ui-sideline-ignore-duplicate t)
(setq lsp-prefer-flymake nil)
(add-hook 'lsp-mode-hook 'lsp-ui-mode))
(ability dap ('lsp)
(dap-mode 1)
(dap-ui-mode 1))
(ability bookmarks ()
(setq bm-restore-repository-on-load t)
(require 'bm)
(cheatsheet-add :group '--Development--
:key "M-p"
:description "Toggle bookmarks")
(cheatsheet-add :group '--Development--
:key "M-]"
:description "Jump to next bookmark")
(cheatsheet-add :group '--Development--
:key "M-["
:description "Jump to previous bookmark")
(global-set-key (kbd "M-p") 'bm-toggle)
(global-set-key (kbd "M-]") 'bm-next)
(global-set-key (kbd "M-[") 'bm-previous)
(setq bm-restore-repository-on-load t)
(setq bm-in-lifo-order t)
(setq bm-cycle-all-buffers t)
(setq-default bm-buffer-persistence t)
(setq bm-repository-file (locate-user-emacs-file "bm-repository"))
;; (add-hook' after-init-hook 'bm-repository-load)
;; (add-hook 'kill-buffer-hook #'bm-buffer-save)
;; ;; Restoring bookmarks
;; (add-hook 'find-file-hooks #'bm-buffer-restore)
;; (add-hook 'after-revert-hook #'bm-buffer-restore)
;; The `after-revert-hook' is not necessary to use to achieve persistence,
;; but it makes the bookmark data in repository more in sync with the file
;; state. This hook might cause trouble when using packages
;; that automatically reverts the buffer (like vc after a check-in).
;; This can easily be avoided if the package provides a hook that is
;; called before the buffer is reverted (like `vc-before-checkin-hook').
;; Then new bookmarks can be saved before the buffer is reverted.
;; Make sure bookmarks is saved before check-in (and revert-buffer)
;; (add-hook 'vc-before-checkin-hook #'bm-buffer-save)
(add-hook' after-init-hook 'bm-repository-load)
(add-hook 'kill-emacs-hook '(lambda nil
(bm-buffer-save-all)
(bm-repository-save))))
(ability livemd ()
"Live markdown preview."
(require 'extensions/development/livemd))
(ability imenu ()
"IMenu integration for FG42"
(require 'imenu)
(require 'imenu-list)
(cheatsheet-add :group '--Development--
:key "C-'"
:description "Toggle IMenu list which shows the symbol definitions based on major mode.")
(cheatsheet-add :group '--Development--
:key "C-<2>"
:description "Search for the definition of the symbol you want anywhere.")
;; (imenu-list-minor-mode)
(setq imenu-list-focus-after-activation t)
(setq imenu-list-auto-resize t)
(global-set-key (kbd "C-'") #'imenu-list-smart-toggle)
(global-set-key (kbd "C-<f2>") #'imenu-anywhere)
(global-set-key (kbd "<f13>") #'imenu-anywhere))
(ability dumb-jump ()
"Easily jump to defination for most langs using ag"
(cheatsheet-add :group '--Development--
:key "M-g o"
:description "Jump to definition in another window")
(cheatsheet-add :group '--Development--
:key "C-u y or M-g j"
:description "Jump to definition in current buffer")
(cheatsheet-add :group '--Development--
:key "C-u i or M-g x"
:description "Jump to definition using an external tool")
(cheatsheet-add :group '--Development--
:key "M-g z"
:description "Jump to definition in another window using an external tool")
(require 'dumb-jump)
(dumb-jump-mode t)
(define-key dumb-jump-mode-map (kbd "M-g o") 'dumb-jump-go-other-window)
(define-key dumb-jump-mode-map (kbd "M-g j") 'dumb-jump-go)
(define-key dumb-jump-mode-map (kbd "C-u y") 'dumb-jump-go)
(define-key dumb-jump-mode-map (kbd "M-g x") 'dumb-jump-go-prefer-external)
(define-key dumb-jump-mode-map (kbd "C-u i") 'dumb-jump-go-prefer-external)
(define-key dumb-jump-mode-map (kbd "M-g z") 'dumb-jump-go-prefer-external-other-window))
(ability git ()
"A wonderful git interface for FG42"
(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)
(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"
(require 'magithub)
(magithub-feature-autoinject t))
;; (ability hl ()
;; "Highligh the current block of code. This ability may slows you down."
;; (require 'hl-sexp)
;; (add-hook 'prog-mode-hook #'hl-sexp-mode))
(ability code-completion ()
"Use company mode to provides a complete auto completion framwork."
(require 'company)
(global-company-mode t)
;; Bigger popup window
(setq company-tooltip-limit 20)
;; Align annotations to the right tooltip border
(setq company-tooltip-align-annotations 't)
;; Decrease delay before autocompletion popup shows
(setq company-idle-delay 0.1)
(setq company-minimum-prefix-length 2)
;; Start autpocompletion only after typing
(setq company-begin-commands '(self-insert-command))
;; Force complete file names on "C-c /" key
(global-set-key (kbd "C-c /") 'company-files)
(add-hook 'after-init-hook 'company-statistics-mode)
(define-key company-active-map "\t" 'company-yasnippet-or-completion)
(setq dabbrev-case-fold-search t)
(add-to-list 'company-backends 'company-dabbrev)
(add-to-list 'company-backends 'company-dabbrev-code))
(ability yas ()
"Snippet configuration."
(let ((snippet_home (concat (file-name-directory
(locate-library "yasnippet-snippets"))
"snippets"))
(my_snippet (concat fg42-home "/lib/snippets")))
(setq yas-snippet-dirs (list my_snippet snippet_home)))
(yas-global-mode 1))
(ability project-management ()
"Ability to manage projects and project navigation."
(projectile-global-mode)
(setq projectile-enable-caching t))
(ability spell ()
"Check spell of any word using ispell. This ability may slows you down"
(global-set-key (kbd "<f2>") 'ispell-word)
(setq flyspell-issue-message-flg nil))
(ability diff-highlight ()
"Highlight the diffs based on VCS."
(add-hook 'prog-mode-hook 'turn-on-diff-hl-mode)
(add-hook 'vc-dir-mode-hook 'turn-on-diff-hl-mode))
(ability auto-pair ()
"Auto pair stuffs like brackets begin/ends etc."
;; TODO: use autopair mode if electric pair was not as good as autopair
(electric-pair-mode))
(ability yaml ()
"YAML editor."
(require 'yaml-mode)
(add-hook 'yaml-mode-hook (lambda () (interactive) (whitespace-mode 1)))
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
(add-to-list 'auto-mode-alist '("\\.sls\\'" . yaml-mode)))
(ability terraform ()
"Terraform editor."
(require 'terraform-mode)
(add-to-list 'auto-mode-alist '("\\.tf\\'" . terraform-mode)))
(ability code-browser ()
"Adds the code browser to FG42."
(require 'neotree)
(setq neo-theme (if (display-graphic-p) 'icons 'arrow))
(cheatsheet-add :group '--Development--
:key "f8"
:description "Toggle project browser sidebar. See ProjectBrowser")
(cheatsheet-add :group '--ProjectBrowser--
:key "n"
:description "Next line")
(cheatsheet-add :group '--ProjectBrowser--
:key "p"
:description "Previous line")
(cheatsheet-add :group '--ProjectBrowser--
:key "g"
:description "Refresh the tree")
(cheatsheet-add :group '--ProjectBrowser--
:key "A"
:description "Maximize/Minimize the project browser")
(cheatsheet-add :group '--ProjectBrowser--
:key "H"
:description "Toggle display hidden files")
(cheatsheet-add :group '--ProjectBrowser--
:key "C-c C-n"
:description "Create a file or create a directory if filename ends with a '/'")
(cheatsheet-add :group '--ProjectBrowser--
:key "C-c C-d"
:description "Delete a file or a directory.")
(cheatsheet-add :group '--ProjectBrowser--
:key "C-c C-r"
:description "Rename a file or a directory.")
(cheatsheet-add :group '--ProjectBrowser--
:key "C-c C-c"
:description "Chande root directory.")
(global-set-key [f8] 'neotree-toggle))
(ability shell ()
"Eshell enhancements."
(cheatsheet-add :group '--Development--
:key "M-`'"
:description "Brings up the eshell")
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(shell-pop-default-directory "$HOME")
;;'(shell-pop-shell-type (quote ("ansi-term" "*ansi-term*" (lambda nil (ansi-term shell-pop-term-shell)))))
'(shell-pop-shell-type (quote ("eshell" "*shell*" (lambda nil (eshell shell-pop-term-shell)))))
;;'(shell-pop-term-shell "/bin/zsh")
'(shell-pop-term-shell "eshell")
'(shell-pop-window-size 30)
'(shell-pop-full-span t)
'(shell-pop-window-position "full")))
;; (require 'eshell-prompt-extras)
;; (with-eval-after-load "esh-opt"
;; (autoload 'epe-theme-lambda "eshell-prompt-extras")
;; (setq eshell-highlight-prompt nil
;; eshell-prompt-function 'epe-theme-lambda))
(ability focus ()
"Provides means for focusing on code review."
(cheatsheet-add :group '--Development--
:key "M-x focus-mode"
:description "Highlights only the paragraph of code which you are reading for better focus."))
(ability pt ()
"Provides fast search ability via platinium search"
(require 'pt)
(cheatsheet-add :group '--Development--
:key "C-c p s s"
:description "Search within a project using pt. It's fast.")
(cheatsheet-add :group '--Development--
:key "C-c p s r"
:description "Search for a regexp in a project.")
(advice-add 'projectile-ag :around #'projectile-pt)
(add-hook 'projectile-mode-hook 'enable-pt-search))
(ability file-browser ()
"A ranger like file browser for FG42"
(cheatsheet-add :group '--Development--
:key "f7"
:description "A ranger like file browser for FG42")
(setq ranger-cleanup-eagerly t)
(setq ranger-show-dotfiles nil)
(global-set-key [f7] 'ranger))
(ability smart-mode-line ()
"Smarter modeline for FG42"
(setq sml/no-confirm-load-theme t)
(setq sml/theme 'respectful)
(sml/setup))
(message "'development' extension has been initialized."))
(provide 'extensions/development/init)

View File

@ -0,0 +1,77 @@
;;; livemd.el --- Realtime Markdown previews for FG42.
;; Copyright (C) 2014-2016 Hrvoje Simic
;; Copyright (C) 2019 Sameer Rahmani <lxsameer@gnu.org>
;; Author: Hrvoje Simic <hrvoje@twobucks.co>
;; Version: 1.0.0
;; Keywords: markdown, preview, live
;; URL: https://gitlab.com/FG42/FG42
;; This is a clone of https://github.com/shime/emacs-livedown
;; Kudos to Hrvoje Simic for his great work.
;;; Commentary:
;; Realtime Markdown previews for Emacs. install `livedown' package
;; using npm like: `npm install -g livedown' and then use `livemd-preview'
;; function to start the dev server.
;;; Code:
(defgroup livemd nil
"Realtime Markdown previews"
:group 'livemd
:prefix "livemd-")
(defcustom livedown-path "livedown"
"Path to livedown executable."
:type 'string
:group 'livemd)
(defcustom livemd-port 1337
"Port on which livemd server will run."
:type 'integer
:group 'livemd)
(defcustom livemd-open t
"Open browser automatically."
:type 'boolean
:group 'livemd)
(defcustom livemd-browser nil
"Open alternative browser."
:type 'string
:group 'livemd)
(defcustom livemd-autostart nil
"Auto-open previews when opening markdown files."
:type 'boolean
:group 'livemd)
;;;###autoload
(defun livemd-preview ()
"Preview the current file in livemd."
(interactive)
(call-process-shell-command (format "livedown stop --port %s &" livemd-port))
(start-process-shell-command
"livedown"
"*fg42-livemd-buffer*"
(format "%s start %s --port %s %s %s "
livedown-path
buffer-file-name
livemd-port
(if livemd-browser (concat "--browser " livemd-browser) "")
(if livemd-open "--open" "")))
(add-hook 'kill-emacs-query-functions (lambda () (livemd-kill t)))
(print (format "%s rendered @ %s" buffer-file-name livemd-port) (get-buffer "emacs-livemd-buffer")))
;;;###autoload
(defun livemd-kill (&optional async)
"Stop the livemd process ASYNC or otherwise."
(interactive)
(let ((stop-livemd (if async 'async-shell-command 'call-process-shell-command)))
(funcall stop-livemd (format "%s stop --port %s &" livedown-path livemd-port))))
(provide 'extensions/development/livemd)
;;; livemd.el ends here

View File

@ -0,0 +1,11 @@
;;; lxgithub.el --- Github integration library for FG42
;;; Commentary:
;;; Code:
(require 'gh)
;; Functions -------------------------------------------------
(gh-issues-api "api")
(provide 'lxgithub)
;;; lxgithub.el ends here

19
lib/extensions/devops.el Normal file
View File

@ -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

View File

@ -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.

View File

@ -0,0 +1,15 @@
(require 'fpkg)
(require 'fg42/extension)
;; Dependencies ----------------------------------
(defun extensions/editor-theme-initialize ()
"Initialize 'editor-theme' extension."
(load-default-theme)
(message "'editor-theme' extension has been initizlied."))
;; Extension -------------------------------------
(extension editor-theme
:version "2.31"
:on-initialize extensions/editor-theme-initialize)
(provide 'extensions/editor-theme)

98
lib/extensions/editor.el Normal file
View File

@ -0,0 +1,98 @@
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/editor/init)
;; Dependencies ----------------------------------
(depends-on 'multiple-cursors)
(depends-on 'expand-region)
(depends-on 'seq)
(depends-on 'ov)
(depends-on 'cheatsheet)
(depends-on 'all-the-icons)
(depends-on 'markdown-mode)
(depends-on 'json-mode)
;; Fast move in the buffer
(depends-on 'avy)
;; Moving between windows
(depends-on 'ace-window)
;; Don't worry unless you're evil this mode won't start
(depends-on 'evil)
;; Resize splitted windows
(depends-on 'windresize)
(depends-on 'eyebrowse)
;; Themes
(depends-on 'spacemacs-theme)
(depends-on 'doom-themes)
;; TODO: Move this to an ability
(depends-on 'solaire-mode)
(with-ability nlinum
(depends-on 'nlinum))
(with-ability spaceline
(depends-on 'spaceline))
(with-ability doom-modeline
(depends-on 'doom-modeline))
(with-ability guru
(depends-on 'guru-mode))
(with-ability tramp
(depends-on 'tramp))
(with-ability ivy
(depends-on 'ivy)
(depends-on 'counsel))
(with-ability selectrum
(depends-on 'selectrum)
(depends-on 'selectrum-prescient)
(depends-on 'ctrlf))
(with-ability ido
(depends-on 'ido)
(depends-on 'ido-completing-read+)
(depends-on 'smex)
(depends-on 'ido-vertical-mode)
(depends-on 'flx-ido))
(with-ability helm
(depends-on 'helm)
(depends-on 'helm-ag)
(depends-on 'helm-themes)
(depends-on 'helm-flx)
(depends-on 'helm-make)
(depends-on 'helm-mode-manager)
(depends-on 'helm-projectile)
(depends-on 'helm-swoop)
(depends-on 'helm-themes))
(with-ability swiper
(depends-on 'swiper))
(with-ability flycheck
(depends-on 'flycheck))
(with-ability emoji
(depends-on 'emojify))
(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))
;; Extension -------------------------------------
(extension editor
:version "2.31"
:on-initialize extensions/editor-initialize)
(provide 'extensions/editor)

View File

@ -0,0 +1,44 @@
;; Vars -------------------------------
(defvar about_fg42_msg "
FG42 %%VERSION%% Copyright © 2010-2018 Sameer Rahmani <lxsameer@gnu.org>
FG42 release under the term of GPLv2.
Home page:
\thttp://fg42.lxsameer.com
Credits:
\tSameer Rahmani (@lxsameer)
\tDanial Parsi (@intuxticated)
\tAmir Houghangi
\tNima Nazari (niman)
\tKeyvan Hedayati (k1-hedayati)
\tBehnam Khan Beigi (@yottanami)
\tEhsan Mahmoudi
"
"About FG42")
;; Functions ---------------------------
(defun about/get_string ()
"Get the about message string"
(let (msg)
(setq msg (replace-regexp-in-string "%%VERSION%%"
FG42-VERSION about_fg42_msg))))
(defun about-fg42 ()
"Show an small about note"
(interactive)
(let (buf msg)
(setq buf (get-buffer-create "*About FG42*"))
(setq msg (about/get_string))
(set-buffer buf)
(insert msg)
(view-buffer buf)))
(define-key-after global-map
[menu-bar help-menu about-fg42]
'("About FG42" . about-fg42-f)
'about-emacs)
(provide 'extensions/editor/about)

View File

@ -0,0 +1,51 @@
;;; Buffers --- All the functions related to buffer management
;;; Commentary:
;;; Code:
(defvar *favorite-buffer* nil)
(defun switch-to-previous-buffer ()
"Switch to previously open buffer.
Repeated invocations toggle between the two most recently open buffers."
(interactive)
(switch-to-buffer (other-buffer (current-buffer) 1)))
(defun buffer-match-p (buf)
"If BUF name match the favorite buffer regexp."
(string-match-p *favorite-buffer* (buffer-name buf)))
(defun switch-and-bury (buf)
"Switch to given BUF and bury it as well."
(interactive)
(bury-buffer buf)
(switch-to-buffer buf))
(defun switch-to-buffer-by-regex ()
"Switch to buffer which the name match the *favorite-buffer* regex."
(interactive)
(if *favorite-buffer*
(switch-and-bury
(car (remove-if-not #'buffer-match-p (buffer-list))))
(eshell)))
(defun switch-to-favorite-buffer ()
"Switch to *favorite-buffer* buffer with is variable assigned to each mode.
For exampe in clojure mode it would the name of repl buffer. The *favorite-buffer* value should be regex matching to the buffer name"
(interactive)
(if *favorite-buffer*
(if (string-match *favorite-buffer* (buffer-name))
(switch-to-previous-buffer)
(switch-to-buffer-by-regex))
(if (string= (buffer-name) "*eshell*")
(switch-to-previous-buffer)
(eshell))))
(defun reset-favorite-buffer-value ()
(message "reseting favorite buffer value...")
(message *favorite-buffer*)
(setq *favorite-buffer* nil))
(add-hook 'change-major-mode-hook 'reset-favorite-buffer-value)
(provide 'extensions/editor/buffers)
;;; buffers.el ends here

View File

@ -0,0 +1,35 @@
;; --------------------------------------------------------------------
;; Groups
;; --------------------------------------------------------------------
(defgroup fg42-user-preferences nil
"User preferences group. this group contain user specified options for
FG42"
:group 'fg42
:tag '"User Preferences"
)
;; --------------------------------------------------------------------
;; Custom Variables
;; --------------------------------------------------------------------
(defcustom developer-name nil
"FG42 use this option as author name in project if the value be non-nil"
:group 'fg42-user-preferences
:type 'string
:tag '"Developer full name"
)
(defcustom developer-email nil
"FG42 use this option as author email in project if the value be non-nil"
:group 'fg42-user-preferences
:type 'string
:tag '"Developer Email"
)
(defcustom fg42-workspace "~/src/"
"FG42 use this option as default path for new project."
:group 'fg42-user-preferences
:type 'string
:tag '"Workspace"
)
(provide 'extensions/editor/custom)

View File

@ -0,0 +1,433 @@
;;; FG42 --- The mighty editor for the emacsians -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani <lxsameer@gnu.org>
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.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 'extensions/editor/buffers)
;; Customizations --------------------------------------------
(defcustom fg42-todo-file "~/.TODO.org"
"Path to your todo file. You can use a tramp address here as well."
:type 'string
:group 'fg42)
;; Hooks -----------------------------------------------------
(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."
(interactive)
(load-file (concat (getenv "FG42_HOME") "/fg42-config.el")))
;;;###autoload
(defun fg42-open-todo ()
(interactive)
(run-hooks 'fg42-before-open-todo-hook)
(find-file fg42-todo-file)
(run-hooks 'fg42-after-open-todo-hook))
;;;###autoload
(defun extensions/editor-initialize ()
"Base plugin initialization."
(if (eq system-type 'darwin)
(progn
(message "Running on the stupid macOS X.")
(exec-path-from-shell-initialize)))
(require 'all-the-icons)
(require 'cheatsheet)
(require 'extensions/editor/utils)
(add-to-list 'custom-theme-load-path
(concat fg42-home "/lib/themes/custom_themes"))
;; Setting user preference based on the race.
(if (is-evil?)
(progn
(require 'evil)
(evil-mode 1)))
(if (is-human?)
(progn
(cua-mode 'emacs)
(cua-selection-mode t)
(setq cua-auto-tabify-rectangles nil)
(transient-mark-mode 1)))
;; Automatically removed excess backups of the file
(setq delete-old-versions t)
;; Font Configuration -----------------------------------
(ability font ()
"Sets the default font to 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")
(cheatsheet-add :group '--Navigation--
:key "M-f"
:description "Move a word to right")
(cheatsheet-add :group '--Navigation--
:key "M-b"
:description "Move a word to left")
(cheatsheet-add :group '--Navigation--
:key "M-{"
:description "Move back a paragraph")
(cheatsheet-add :group '--Navigation--
:key "M-}"
:description "Move forward by a paragraph")
(global-set-key (kbd "C-?") 'cheatsheet-show)
;; Fast Move in the buffer
(global-set-key (kbd "M-1") 'avy-goto-word-or-subword-1)
(cheatsheet-add :group '--Navigation--
:key "M-1"
:description "Jump to the a word or subword in the buffer")
;; Remove splash screen
(setq inhibit-splash-screen t)
;; scratch should be scratch
(setq initial-scratch-message nil)
(ability highligh-current-line ()
"Highlights the current line."
(global-hl-line-mode t))
(ability flycheck ()
"Check syntax on the fly using flycheck."
(require 'flycheck)
(add-hook 'prog-mode-hook 'global-flycheck-mode)
(add-hook 'after-init-hook 'global-flycheck-mode))
;; ACE Window
(global-set-key (kbd "C-<tab>") 'ace-window)
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
;; Tramp configuration -------------------------------------
(ability tramp ()
(setq tramp-default-method "ssh")
(cheatsheet-add :group '--EDITOR--
:key "f9"
:description "Open up your todo file. checkout `fg42-todo-file` var and `fg42-open-todo` function.")
(global-set-key [f9] 'fg42-open-todo))
(global-unset-key (kbd "C-o"))
(global-unset-key (kbd "C-v"))
(cheatsheet-add :group '--EDITOR--
:key "C-s-n"
:description "Move a paragraph forward")
(cheatsheet-add :group '--EDITOR--
:key "C-s-p"
:description "Move a paragraph backward")
(global-set-key (kbd "C-s-n") 'forward-paragraph)
(global-set-key (kbd "C-s-p") 'backward-paragraph)
;; replace strings
(global-set-key (kbd "C-c M-s") 'replace-string)
;; Basic Key bindings
(global-set-key (kbd "\C-c m") 'menu-bar-mode)
(global-set-key (kbd "<f2>") 'goto-line)
(global-set-key (kbd "M-TAB") 'switch-to-previous-buffer)
(global-set-key (kbd "M-`") 'switch-to-favorite-buffer)
;; Don't allow tab as indent
(setq-default indent-tabs-mode nil)
(ability nlinum ()
"Faster alternative to linum-mode"
(require 'nlinum)
(setq nlinum-highlight-current-line t)
(global-nlinum-mode t))
;; Default indent width
(setq tab-width 2)
(add-hook 'before-save-hook 'delete-trailing-whitespace)
;; Enhancements ---------------------------------------------
;; Global configurations
(tool-bar-mode -1)
(scroll-bar-mode -1)
(setq x-select-enable-clipboard t)
(column-number-mode t)
;; linum mode
(ability linum ()
"Line numbering ability"
(global-linum-mode)
(setq linum-format " %3d "))
(ability hide-menu ()
"Hides the emacs menu completely."
(menu-bar-mode -1))
(show-paren-mode t)
(cua-selection-mode t)
(ability thin-cursor ()
(setq-default cursor-type 'bar))
(ability nonblinker-cursor ()
(blink-cursor-mode -1))
;; expand-region -------------------------------------------
(global-set-key (kbd "C-=") 'er/expand-region)
(global-set-key (kbd "C-+") 'er/contract-region)
;; Multiple cursor -----------------------------------------
;; multiple cursor configurations
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-SPC ") 'mc/mark-all-like-this)
;; Reload FG42
(define-key global-map (kbd "C-<f5>") 'fg42-reload)
;; Key Chord ------------------------------------------------
;; (require 'key-chord)
;; (key-chord-mode 1)
;; (key-chord-define-global "hj" 'undo)
;; (key-chord-define-global "kl" 'right-word)
;; (key-chord-define-global "sd" 'left-word)
;; (key-chord-define-global "m," 'forward-paragraph)
;; (key-chord-define-global "p[" 'backward-paragraph)
;; HideShow -------------------------------------------------------
(global-set-key (kbd "C-\-") 'hs-toggle-hiding)
(hs-minor-mode)
;; Guru Configuration
(ability guru ()
(require 'guru-mode)
(guru-global-mode +1))
;; IDO configurations ---------------------------------------------
(ability ido ()
(require 'ido)
(require 'flx-ido)
(require 'ido-vertical-mode)
(ido-everywhere t)
(require 'ido-completing-read+)
(ido-ubiquitous-mode 1)
(ido-mode t)
(ability smex ()
(smex-initialize)
(global-set-key (kbd "M-x") 'smex))
(flx-ido-mode 1)
(setq ido-use-faces nil)
(setq ido-use-filename-at-point nil)
(setq ido-enable-flex-matching t)
(ido-vertical-mode 1))
(ability selectrum ()
"Selectrum is a better replacement for IDO and Ivy"
(require 'selectrum)
(require 'selectrum-prescient)
(selectrum-mode +1)
(selectrum-prescient-mode +1)
(prescient-persist-mode +1)
(when-not-wm
(require 'ctrlf)
(ctrlf-mode +1))
(setq prescient-filter-method '(literal fuzzy regexp initialism)))
(ability ivy ()
"Completion using ivy."
(require 'ivy)
(require 'counsel)
(ivy-mode 1)
(setq ivy-use-virtual-buffers t)
(setq enable-recursive-minibuffers t)
(global-set-key (kbd "M-x") 'counsel-M-x)
(global-set-key (kbd "<f1> f") 'counsel-describe-function)
(global-set-key (kbd "<f1> v") 'counsel-describe-variable)
(global-set-key (kbd "<f1> l") 'counsel-find-library)
(global-set-key (kbd "C-c k") 'counsel-ag)
(global-set-key (kbd "C-c C-r") 'ivy-resume))
;; Swiper ---------------------------------------------------
(ability swiper (ivy)
"Replace default isearch with swiper"
(global-set-key "\C-s" 'swiper)
(global-set-key "\C-r" 'swiper))
;; (with-ability ido
;; (global-set-key (kbd "C-x b") 'ido-switch-buffer)))
(ability tabbar ()
(tabbar-mode 1))
;; Helm -----------------------------------------------------
(ability helm ()
"Helm is an emacs incremental completion and selection narrowing framework"
(require 'helm)
(require 'helm-flx)
(global-set-key (kbd "C-c h") 'helm-command-prefix)
(global-set-key (kbd "M-x") 'helm-M-x)
(global-set-key (kbd "C-x C-f") 'helm-find-files)
(global-unset-key (kbd "C-x c"))
(define-key helm-map (kbd "<tab>")
'helm-execute-persistent-action)
(define-key helm-map (kbd "C-i")
'helm-execute-persistent-action)
(define-key helm-map (kbd "C-z")
'helm-select-action)
(when (executable-find "curl")
(setq helm-google-suggest-use-curl-p t))
(setq helm-split-window-in-side-p t
helm-move-to-line-cycle-in-source t
helm-ff-search-library-in-sexp t
helm-scroll-amount 8
helm-ff-file-name-history-use-recentf t)
(setq helm-flx-for-helm-find-files t
helm-flx-for-helm-locate t)
(helm-flx-mode +1)
(helm-mode 1))
;; Session Management ---------------------------------------
(ability desktop-mode ()
"Save your current working buffers and restore later"
(desktop-save-mode 1))
(ability emoji ()
"Adds support for emoji support in FG42. (github style)"
(require 'emojify)
(add-hook 'after-init-hook #'global-emojify-mode))
(set-fontset-font "fontset-default"
(cons (decode-char 'ucs #x0627)
(decode-char 'ucs #x0649))
"Vazir")
(set-fontset-font "fontset-default"
(cons (decode-char 'ucs #xFE8D)
(decode-char 'ucs #xFEF0))
"Vazir")
(set-fontset-font "fontset-default"
(cons (decode-char 'ucs #x064e)
(decode-char 'ucs #x06a9))
"Vazir")
(set-fontset-font "fontset-default"
(cons (decode-char 'ucs #x06F0)
(decode-char 'ucs #x00A0))
"Vazir")
;; Backup files ---------------------------------------------
(ability backup-files ()
;; Put them in one nice place if possible
(if (file-directory-p "~/.backup")
(setq backup-directory-alist '(("~/.backup")))
(make-directory "~/.backup"))
(setq backup-by-copying t))
(ability versioned-backup ('backup-files)
(setq delete-old-versions t)
(setq version-control t)
(setq kept-new-versions 3)
(setq kept-old-versions 2))
;; get rid of yes-or-no questions - y or n is enough
(defalias 'yes-or-no-p 'y-or-n-p)
(setup-utils)
(setq my-path (file-name-directory load-file-name))
;; Load about submenu
(require 'extensions/editor/version)
(require 'extensions/editor/about)
(require 'extensions/editor/custom)
(require 'extensions/editor/session-management)
(require 'extensions/editor/lxdrive-mode)
(require 'extensions/editor/lxmodeline)
(message "'editor' extension has been initialized."))
(provide 'extensions/editor/init)
;;; init.el ends here

View File

@ -0,0 +1,94 @@
;;; lxdrive-mode --- A minor mode for fast cursor movement
;;; Commentary:
;;; Code:
(require 'expand-region)
(setq original-global-map global-map)
(boundp 'lxdrive-minor-mode)
(defun turn-off-lxdrive ()
"Toggle lxdrive mode."
(interactive)
(lxdrive-minor-mode nil)
(setq lxdrive-minor-mode nil)
(use-global-map original-global-map))
(defun turn-on-lxdrive ()
"Toggle lxdrive mode."
(interactive)
(lxdrive-minor-mode t)
(use-global-map lxdrive-mode-map))
(defun turn-off-and-command ()
"Turn off the lxdrive mode and run the counsel command."
(interactive)
(turn-off-lxdrive)
(counsel-M-x))
(defun switch-other ()
"Switch to the most recent buffer."
(interactive)
(switch-to-buffer (other-buffer)))
(defvar lxdrive-mode-map
(let ((map (make-sparse-keymap)))
;; Movement
(define-key map (kbd "l") 'forward-char)
(define-key map (kbd "j") 'backward-char)
(define-key map (kbd "i") 'previous-line)
(define-key map (kbd "k") 'next-line)
(define-key map (kbd "u") 'backward-word)
(define-key map (kbd "o") 'forward-word)
(define-key map (kbd "n") 'backward-paragraph)
(define-key map (kbd "m") 'forward-paragraph)
(define-key map (kbd "TAB") 'indent-for-tab-command)
(define-key map (kbd "`") 'cua-set-mark)
(define-key map (kbd "=") 'er/expand-region)
(define-key map (kbd "]") 'forward-page)
(define-key map (kbd "[") 'backward-page)
(define-key map (kbd "e") 'move-end-of-line)
(define-key map (kbd "a") 'move-beginning-of-line)
(define-key map (kbd "<f2>") 'go-to-line)
(define-key map (kbd "C-TAB") 'other-window)
(define-key map (kbd "M-TAB") 'switch-other)
;; Actions
(define-key map (kbd "RET") 'newline)
(define-key map (kbd "d") 'delete-char)
(define-key map (kbd "<backspace>") 'delete-backward-char)
(define-key map (kbd "y") 'cua-paste)
(define-key map (kbd "C-w") 'kill-region)
(define-key map (kbd "M-w") 'kill-ring-save)
(define-key map (kbd "h") 'kill-and-join-forward)
(define-key map (kbd "g") 'keyboard-quit)
(define-key map (kbd "z") 'undo)
(define-key map (kbd "/") 'undo)
(define-key map (kbd "M-x") 'turn-off-and-command)
(define-key map (kbd "C-x C-s") 'save-buffer)
(define-key map (kbd "SPC") 'self-insert-command)
;;(define-key map (kbd "ESC ESC") 'turn-off-lxdrive)
(define-key map (kbd "q") 'turn-off-lxdrive)
(define-key map (kbd "M-SPC") 'turn-off-lxdrive)
map)
"Keymap for lxdrive-minor-mode.")
(define-minor-mode lxdrive-minor-mode
"A minor mode so that my key settings override annoying major modes."
:global t
:lighter " lx")
;;(global-set-key (kbd "ESC ESC") 'turn-on-lxdrive)
(global-set-key (kbd "M-SPC") 'turn-on-lxdrive)
(global-set-key (kbd "M-TAB") 'switch-other)
(with-ability spaceline
(spaceline-toggle-lxdrive-on))
(provide 'extensions/editor/lxdrive-mode)
;;; lxdrive-mode ends here

View File

@ -0,0 +1,33 @@
;;; lxmode-line --- A small utility library to toggle the modeline.
;;; Commentary:
;;; Code:
;; (require 'doom-modeline)
;; (doom-modeline-def-segment lxdrive-info
;; "Show the status of lxdrive mode"
;; (if (and (boundp 'lxdrive-minor-mode) lxdrive-minor-mode)
;; (list " " (all-the-icons-faicon "arrows" :height 0.8 :v-adjust 0.15 :face 'all-the-icons-lgreen))
;; (list " " (all-the-icons-faicon "pencil" :height 0.8 :v-adjust 0.15))))
;; (doom-modeline-def-modeline 'fg42-mode-line
;; '(bar lxdrive-info matches buffer-info buffer-position parrot selection-info)
;; '(process vcs checker))
;; (defun setup-custom-doom-modeline ()
;; "Setup fg42 modeline."
;; (doom-modeline-set-modeline 'fg42-mode-line 'default))
;; (with-ability doom-modeline
;; (add-hook 'doom-modeline-mode-hook 'setup-custom-doom-modeline)
;; (setq doom-modeline-height 15)
;; (setq doom-modeline-buffer-encoding nil)
;; (setq doom-modeline-lsp nil)
;; (setq doom-modeline-mu4e nil)
;; (setq doom-modeline-irc nil)
;; (setq doom-modeline-buffer-file-name-style 'truncate-with-project)
;; (doom-modeline-mode t))
(provide 'extensions/editor/lxmodeline)
;;; lxmodeline ends here

View File

@ -0,0 +1,47 @@
;; ---------------------------------------------------------------------
;; Variables
;; ---------------------------------------------------------------------
(defvar my-desktop-session-dir
(concat (getenv "HOME") "/.tmp/")
"*Directory to save desktop sessions in")
(defvar my-desktop-session-name-hist nil
"Desktop session name history")
;; ---------------------------------------------------------------------
;; Functions
;; ---------------------------------------------------------------------
(defun my-desktop-save (&optional name)
"Save desktop with a name."
(interactive)
(unless name
(setq name (my-desktop-get-session-name "Save session as: ")))
(make-directory (concat my-desktop-session-dir name) t)
(desktop-save (concat my-desktop-session-dir name) t))
(defun my-desktop-read (&optional name)
"Read desktop with a name."
(interactive)
(unless name
(setq name (my-desktop-get-session-name "Load session: ")))
(desktop-read (concat my-desktop-session-dir name)))
(defun my-desktop-get-session-name (prompt)
(completing-read prompt (and (file-exists-p my-desktop-session-dir)
(directory-files my-desktop-session-dir))
nil nil nil my-desktop-session-name-hist))
(define-key-after global-map
[menu-bar file load-session] '("Load Session" . my-desktop-read)
'dired)
(define-key-after
global-map [menu-bar file save-session]
'("Save Session" . my-desktop-save) 'load-session)
(define-key global-map (kbd "<f11>") 'my-desktop-read)
(define-key global-map (kbd "<f12>") 'my-desktop-save)
(provide 'extensions/editor/session-management)

View File

@ -0,0 +1,45 @@
;; Functions -----------------------------
;;;###autoload
(defun comment-dwim-line (&optional arg)
"Replacement for the comment-dwim command.
If no region is selected and current line is
not blank and we are not at the end of the line,
then comment current line.
Replaces default behaviour of comment-dwim, when
it inserts comment at the end of the line."
;; Original idea from
;; http://www.opensubscriber.com/message/emacs-devel@gnu.org/10971693.html
(interactive "*P")
(comment-normalize-vars)
(if (and (not (region-active-p))
(not (looking-at "[ \t]*$")))
(comment-or-uncomment-region (line-beginning-position)
(line-end-position))
(comment-dwim arg)))
;;;###autoload
(defun kill-and-join-forward (&optional arg)
"If at end of line, join with following; otherwise kill line.
Deletes whitespace at join.
http://www.emacswiki.org/emacs/AutoIndentation"
(interactive "P")
(if (and (eolp) (not (bolp)))
(progn (forward-char 1)
(just-one-space 0)
(backward-char 1)
(kill-line arg))
(kill-line arg)))
;;;###autoload
(defun setup-utils ()
"Setup several utitlies for FG42"
(global-set-key (kbd "C-k") 'kill-and-join-forward)
(global-set-key (kbd "M-;") 'comment-dwim-line)
(global-set-key (kbd "M-j") (lambda ()
(interactive) (join-line -1))))
(provide 'extensions/editor/utils)

View File

@ -0,0 +1,4 @@
(defconst FG42-VERSION "2.31.0"
"Global version of FG42")
(provide 'extensions/editor/version)

0
lib/extensions/github.el Normal file
View File

22
lib/extensions/go.el Normal file
View File

@ -0,0 +1,22 @@
;;; GoExtention --- Enable Golang support in FG42
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/go/init)
;; dependencies
(depends-on 'go-mode)
(depends-on 'go-add-tags)
(depends-on 'go-stacktracer)
(depends-on 'gotest)
(depends-on 'exec-path-from-shell)
(extension go
:version 0.0.1
:on-initialize extensions/go-initialize
:docs "lib/extensions/go/readme.org")
(provide 'extensions/go)
;;; go.el ends here

40
lib/extensions/go/init.el Normal file
View File

@ -0,0 +1,40 @@
;;; go-init --- The entry point for golang extension
;;; Commentary:
;;; Code:
(defun fg42-go-hook ()
;; move to action
"Set's up emacs hooks and turn necessary modes on."
(lsp-register-custom-settings
'(("gopls.completeUnimported" t t)
("gopls.staticcheck" t t)))
(setq lsp-headerline-breadcrumb-enable nil)
(lsp)
(with-ability yas
(yas-minor-mode-on))
(setq-local company-backends '(company-capf company-dabbrev company-dabbrev-code))
(add-hook 'before-save-hook #'lsp-format-buffer t t)
(add-hook 'before-save-hook #'lsp-organize-imports t t)
;; (add-hook 'before-save-hook #'eglot-format t t)
;; (add-hook 'before-save-hook #' t t)
(local-set-key (kbd "M-.") #'godef-jump)
(local-set-key (kbd "M-*") 'pop-tag-mark))
(defun go-path ()
"Gets gopath from OS env."
(exec-path-from-shell-copy-env "GOPATH"))
(defun go-path-binary ()
"Gets Go binaries path."
(concat (go-path) "/bin"))
(defun extensions/go-initialize ()
"Initialize Golang extension."
(exec-path-from-shell-initialize)
(add-to-list 'exec-path (go-path-binary))
(add-hook 'go-mode-hook 'fg42-go-hook))
(provide 'extensions/go/init)
;;; init ends here.

23
lib/extensions/godot.el Normal file
View File

@ -0,0 +1,23 @@
;;; GodotExtension --- Godot Game engine development in FG42.
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/godot/init)
;; Dependencies ----------------------------------
(depends-on 'gdscript-mode)
(defun godot-doc ()
"TBD"
"TBD")
;; Extension -------------------------------------
(extension godot
:version "2.32"
:on-initialize extensions/godot-initialize
:docs "lib/extensions/godot/readme.org")
(provide 'extensions/godot)
;;; godot.el ends here

View File

@ -0,0 +1,19 @@
;;; Godot --- Enables Godot game engine integration with FG42
;;; Commentary:
;;; Code:
;; (defun setup-gdscript()
;; (setq-default indent-tabs-mode nil)
;; (setq tab-width 2)
;; (setq gdscript-tabs-mode t)
;; (setq gdscript-tab-width 2))
;;;###autoload
(defun extensions/godot-initialize ()
(add-to-list 'auto-mode-alist '("\\.gd$" . gdscript-mode))
(add-hook 'gdscript-mode-hook 'lsp))
(provide 'extensions/godot/init)
;;; init.el ends here

22
lib/extensions/haskell.el Normal file
View File

@ -0,0 +1,22 @@
;;; HaskellExtension --- Enables haskell development on FG42
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/haskell/init)
;; Dependencies ----------------------------------
(depends-on 'haskell-mode)
(defun haskell-doc ()
"something fun")
;; Extension -------------------------------------
(extension haskell
:version "2.32"
:on-initialize extensions/haskell-initialize
:docs "lib/extensions/haskell/readme.org")
(provide 'extensions/haskell)
;;; haskell.el ends here

View File

@ -0,0 +1,11 @@
;;; HaskellExtension --- Enables haskell development on FG42
;;; Commentary:
;;; Code:
;;;###autoload
(defun extensions/haskell-initialize ())
(provide 'extensions/haskell/init)
;; init.el ends here

22
lib/extensions/irc.el Normal file
View File

@ -0,0 +1,22 @@
;;; IRCExtension --- Enables irc client on FG42
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/irc/init)
;; Dependencies ----------------------------------
(depends-on 'rcirc-notify)
(defun irc-doc ()
"TBD"
"TBD")
;; Extension -------------------------------------
(extension irc
:version "2.32"
:on-initialize extensions/irc-initialize
:docs "lib/extensions/irc/readme.org")
(provide 'extensions/irc)
;;; irc.el ends here

View File

@ -0,0 +1,80 @@
;;; IRCExtension --- Enables irc client on FG42
;;; Commentary:
;;; Code:
(defvar irc-servers
'(("irc.freenode.net"
:port 6697
:encryption tls
:channels ("#5hit")))
"A list of servers and channels to connect to.")
(defvar irc-auth nil
"The irc authentication credentials.
This would overridethe default behaviour which is based onauth-sources.")
(defvar irc-nickname "fg42-user"
"The default nickname for irc. ")
(defun irc/extract-secrets-from-auth-source ()
"Extract the irc authenticate data from the auth-sources.
As an example for ~/.authinfo.gpg should contain:
machine freenode login <nickname> port nickserv password <password>
Also the auth-sources should be set correctly.
It returns nil if no password is available."
(let ((auth-list '()))
(dolist (p (auth-source-search :port '("nickserv")
:require '(:port :user :secret)))
(let ((secret (plist-get p :secret))
(method (intern (plist-get p :port))))
(add-to-list 'auth-list
(list (plist-get p :host)
method
(plist-get p :user)
(if (functionp secret)
(funcall secret)
secret)))))
auth-list))
;;;###autoload
(defun irc/setup ()
"Setup the rcirc library which distributes with Emacs."
(set (make-local-variable 'scroll-conservatively) 8192)
(setq gnutls-min-prime-bits 2048))
(defun irc/connect ()
"Connects to IRC."
(interactive)
(require 'rcirc)
(require 'rcirc-notify)
;; Turns off keychain integration
(setenv "GPG_AGENT_INFO" nil)
;; Turn on debugging if the global debuging was enabled
(setq rcirc-debug-flag debug-on-error)
(setq rcirc-server-alist irc-servers)
(setq rcirc-authinfo (or (irc/extract-secrets-from-auth-source)
irc-auth))
(setq rcirc-default-nick irc-nickname)
(rcirc-notify-add-hooks)
(rcirc-track-minor-mode 1)
(rcirc nil))
;;;###autoload
(defun extensions/irc-initialize ()
"Initialize the irc extention."
;; Keep input line at bottom.
(add-hook 'rcirc-mode-hook 'irc/setup)
(ability irc-spell-checking ()
(add-hook 'rcirc-mode-hook (lambda ()
(flyspell-mode 1)))))
;
(provide 'extensions/irc/init)
;;; init.el ends here

31
lib/extensions/java.el Normal file
View File

@ -0,0 +1,31 @@
;;; JavaExtension --- Enables java development on FG42
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/java/init)
;; Dependencies ----------------------------------
(depends-on 'gradle-mode)
(depends-on 'flycheck-gradle)
(depends-on 'groovy-mode)
(with-ability lsp-java
(depends-on 'lsp-java))
;;(depends-on 'dap-java))
(defun java-doc ()
"TBD")
;; Extension -------------------------------------
(extension java
:version "2.32"
:on-initialize extensions/java-initialize
:docs "lib/extensions/java/readme.org")
(provide 'extensions/java)
;;; java.el ends here

View File

@ -0,0 +1,28 @@
;;; java-init --- The entry point for common lisp extension
;;; Commentary:
;;; Code:
;;;###autoload
(defun extensions/java-initialize ()
"Initialize the common Lisp extension."
(add-to-list 'auto-mode-alist
'("\\.gradle\\'" . groovy-mode))
(require 'gradle-mode)
(add-hook 'java-mode-hook
'(lambda()
;; To fix the indentation of function arguments
(c-set-offset 'arglist-intro '+)
(setq java-basic-offset 2)
(setq c-basic-offset 2)
(ability lsp-java ('lsp)
(setq lsp-java-server-install-dir fg42-tmp)
(lsp))
(ability dap-java ('dap)
(require 'dap-java))
(gradle-mode 1))))
(provide 'extensions/java/init)
;;; init ends here

View File

@ -0,0 +1,30 @@
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/javascript/init)
;; Dependencies ----------------------------------
(depends-on 'coffee-mode)
(depends-on 'js2-mode)
(depends-on 'rjsx-mode)
(depends-on 'js2-refactor)
(depends-on 'smart-forward)
(depends-on 'ac-js2)
(depends-on 'pug-mode)
(with-ability prettierjs
(depends-on 'prettier-js))
;;(depends-on 'tern)
(with-ability indium
(depends-on 'indium))
(depends-on 'company-web)
(depends-on 'jquery-doc)
;; Extension -------------------------------------
(extension javascript
:version "2.31"
:on-initialize extensions/javascript-initialize)
(provide 'extensions/javascript)

View File

@ -0,0 +1,74 @@
;; Functions -------------------------------------------------
;;;###autoload
(defun js2-careless-semicolon ()
"Don't give a shit about semicolons. According to javascript's bullshit standard."
(interactive)
(setq js2-strict-missing-semi-warning nil)
(js2-mode))
;;;###autoload
(defun javascript-callback ()
(require 'jquery-doc)
(js2-minor-mode t)
;; FIXME: don't hard code the indent size
(setq js2-basic-offset 2)
(define-key js2-mode-map (kbd "C-c C-d") 'js2-jump-to-definition)
(require 'company-web-jade)
(define-key js2-mode-map (kbd "C-'") 'company-web-jade)
(jquery-doc-setup))
;;;###autoload
(defun extensions/javascript-initialize ()
"Javascript development plugin initialization."
(ability indium ()
(defun init-indium ()
(interactive)
(require 'indium))
(add-hook 'js2-mode-hook #'init-indium)
;(add-hook 'js2-mode-hook #'jade-interaction-mode)
)
(ability js-complition ()
(require 'ac-js2)
(add-to-list 'company-backends 'ac-js2-company))
(with-ability pug-editor ()
"Pug template editor."
(setq pug-tab-width 2)
(add-to-list 'auto-mode-alist '("\\.pug\\'" . (lambda ()
(require 'pug-mode)
(pug-mode)
(setq pug-tab-width 2)))))
(ability javascript-editor ('flycheck)
"Gives FG42 the ability to edit javascript."
(autoload 'js2-mode "js2-mode" "Javascript mode")
;(autoload 'tern-mode "tern.el" nil t)
(add-to-list 'auto-mode-alist '("\\.js\\'" . rjsx-mode))
;(add-to-list 'auto-mode-alist '("\\.jsx\\'" . js2-mode))
(add-to-list 'auto-mode-alist '("\\.json\\'" . js2-mode))
(add-hook 'js2-mode-hook 'javascript-callback)
(setq js2-highlight-level 3)
(require 'smart-forward)
(global-set-key (kbd "M-<up>") 'smart-up)
(global-set-key (kbd "M-<down>") 'smart-down)
(global-set-key (kbd "M-<left>") 'smart-backward)
(global-set-key (kbd "M-<right>") 'smart-forward))
(ability coffee-editor ()
"Gives FG42 ability to edit coffee script files."
(custom-set-variables '(coffee-tab-width 2)))
(message "'javascript' extension has been initialized."))
(provide 'extensions/javascript/init)

21
lib/extensions/latex.el Normal file
View File

@ -0,0 +1,21 @@
;;; latex-extension --- Latex extension for FG42
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/latex/init)
;TODO: add to MELPA and remove lsp-latex.el file beside init.el
;(with-ability lsp-latex (depends-on 'lsp-latex))
(defun latex-doc ()
"something fun")
;; Extension -------------------------------------
(extension latex
:version "2."
:on-initialize extensions/latex-initialize
:docs "lib/extensions/latex/readme.org")
(provide 'extensions/latex)
;;; latex.el ends here

View File

@ -0,0 +1,19 @@
;;; latex-init --- The entry point for latex extension
;;; Commentary:
;;; Code:
(defun latex-run-lsp ()
(interactive)
"Run lsp-mode and set the texlab executable path."
(require 'extensions/latex/lsp-latex)
(setq lsp-latex-texlab-executable "texlab")
(lsp))
;;;###autoload
(defun extensions/latex-initialize ()
"Latex autocompletion support."
(ability lsp-latex ('lsp)
(add-hook 'tex-mode-hook 'latex-run-lsp)))
(provide 'extensions/latex/init)
;;; init.el ends here

View File

@ -0,0 +1,134 @@
;;; lsp-latex.el --- lsp-mode client for LaTeX. -*- lexical-binding: t; -*-
;; Copyright (C) 2019 ROCKTAKEY
;; Author: ROCKTAKEY <rocktakey@gmail.com>
;; Keywords: languages, extensions, tex
;; Version: 1.0.0
;; Package-Requires: ((emacs "25.1") (lsp-mode "6.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 <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
(require 'lsp-mode)
(defgroup lsp-latex nil
"Language Server Protocol client for LaTeX."
:group 'lsp-mode)
;; Under texlab v1.0
(defcustom lsp-latex-java-executable "java"
"Executable command to run Java.
This is used with `lsp-latex-java-argument-list'."
:group 'lsp-latex
:type 'string)
(defcustom lsp-latex-java-argument-list '("-jar")
"List of arguments passed to `lsp-latex-java-executable'."
:group 'lsp-latex
:risky t
:type '(repeat string))
(defcustom lsp-latex-texlab-jar-file 'search-from-exec-path
"File named \"texlab.jar\".
You can install it from https://github.com/latex-lsp/texlab/releases/tag/v0.4.1 .
The value can be a string (path to \"texlab.jar\") or the symbol search-from-exec-path. See the docstring of `lsp-latex-get-texlab-jar-file'."
:group 'lsp-latex
:type '(choice string (const search-from-exec-path)))
(defcustom lsp-latex-texlab-jar-argument-list '()
"List of arguments passed to `lsp-latex-texlab-jar-file'. "
:group 'lsp-latex
:type '(repeat string))
(defun lsp-latex-get-texlab-jar-file ()
"Return the path to \"texlab.jar\".
If `lsp-latex-texlab-jar-file' is a string, return it.
If `lsp-latex-texlab-jar-file' is the symbol search-from-exec-path, then search a file named \"texlab.jar\" from `exec-path'."
(cond
((stringp lsp-latex-texlab-jar-file)
lsp-latex-texlab-jar-file)
((eq lsp-latex-texlab-jar-file 'search-from-exec-path)
(locate-file "texlab.jar" exec-path))
(t (error "invalid value of `lsp-latex-texlab-jar-file'"))))
;; texlab v1.0 or more
(defcustom lsp-latex-texlab-executable
(cond ((eq system-type 'windows-nt)
"texlab.exe")
(t "texlab"))
"Exeucutable command to run texlab.
Runned with the arguments `lsp-latex-texlab-executable-argument-list'."
:group 'lsp-latex
:type 'string)
(defcustom lsp-latex-texlab-executable-argument-list '()
"list of Arguments passed to `lsp-latex-texlab-executable'."
:group 'lsp-latex
:type '(repeat string))
(add-to-list 'lsp-language-id-configuration '(".*\\.tex$" . "latex"))
(defun lsp-latex-new-connection ()
""
(let (jar-file)
(cond
((locate-file lsp-latex-texlab-executable exec-path)
(cons lsp-latex-texlab-executable
lsp-latex-texlab-executable-argument-list))
((setq jar-file (lsp-latex-get-texlab-jar-file))
(append
(cons
lsp-latex-java-executable
lsp-latex-java-argument-list)
(cons
jar-file
lsp-latex-texlab-jar-argument-list)))
(t
(error "No executable \"texlab\" file")))))
;; Copied from `lsp-clients--rust-window-progress' in `lsp-rust'.
(defun lsp-latex-window-progress (_workspace params)
"Progress report handling.
PARAMS progress report notification data."
;; Minimal implementation - we could show the progress as well.
(lsp-log (gethash "title" params)))
(lsp-register-client
(make-lsp-client :new-connection
(lsp-stdio-connection
#'lsp-latex-new-connection)
:major-modes '(tex-mode yatex-mode latex-mode)
:server-id 'texlab
:notification-handlers
(lsp-ht
("window/progress"
'lsp-latex-window-progress))))
(provide 'extensions/latex/lsp-latex)
;;; lsp-latex.el ends here

17
lib/extensions/lua.el Normal file
View File

@ -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

View File

@ -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.

22
lib/extensions/org.el Normal file
View File

@ -0,0 +1,22 @@
;;; OrgExtention --- Enable org-mode support in FG42
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/org/init)
;; dependencies
(depends-on 'org)
(depends-on 'org-bullets)
(depends-on 'org-ql)
(depends-on 'org-roam)
(depends-on 'org-make-toc)
(depends-on 'org-timeline)
(extension org
:version 0.0.1
:on-initialize extensions/org-initialize
:docs "lib/extensions/org/readme.org")
(provide 'extensions/org)
;;; rust.el ends here

View File

@ -0,0 +1,24 @@
;;; org-init --- The entry point for Org extension
;;; Commentary:
;;; Code:
(defun org-setup ()
(add-hook 'completion-at-point-functions 'pcomplete-completions-at-point nil t)
(setq org-agenda-files '("~/orgs/main.org"))
;; Need to be set in ~/.fg42.el
;; (setq org-directory "~/orgs/")
(setq org-default-notes-file (concat org-directory "/notes.org"))
(require 'org-bullets)
(org-bullets-mode 1)
(define-key org-mode-map (kbd "C-c a") #'org-agenda))
;;;###autoload
(defun extensions/org-initialize ()
"Initialize Rust extension."
(add-hook 'org-mode-hook #'org-setup))
(provide 'extensions/org/init)
;;; init.el ends here

13
lib/extensions/php.el Normal file
View File

@ -0,0 +1,13 @@
(require 'fpkg)
(require 'fg42/extension)
(require 'extensions/php/init)
;; Dependencies ----------------------------------
(depends-on 'web-mode)
;; Extension -------------------------------------
(extension php
:version "2.31"
:on-initialize extensions/php-initialize)
(provide 'extensions/php)

View File

@ -0,0 +1,8 @@
;; Functions ----------------------------------
(defun extensions/php-initialize ()
"PHP extensions initialization function"
(add-to-list 'auto-mode-alist '("\\.php$" . web-mode))
)
(provide 'extensions/php/init)

Some files were not shown because too many files have changed in this diff Show More