├── .github ├── CODEOWNERS ├── config │ ├── gitleaks.toml │ ├── lychee.toml │ ├── markdown-link-check.json │ ├── markdown-lint.jsonc │ ├── megalinter.yaml │ └── secretlintrc.json ├── pull_request_template.md └── workflows │ ├── changelog-check.yaml │ ├── megalinter.yaml │ ├── publish-book.yaml │ ├── scheduled-stale-check.yaml │ └── scheduled-version-check.yaml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── SUMMARY.md ├── docs ├── .nojekyll ├── assets │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── favicon.svg │ ├── images │ │ ├── practicalli-logo.png │ │ └── social │ │ │ └── README.md │ ├── practicalli-logo.svg │ └── stylesheets │ │ └── extra.css ├── basics │ ├── evil-editing.md │ ├── evil-tools.md │ ├── getting-help.md │ ├── index.md │ ├── projects.md │ ├── snippets.md │ ├── speaking-evil.md │ ├── structural-editing.md │ ├── vim-quick-reference.md │ └── workspaces.md ├── clojure-workflow │ └── index.md ├── index.md ├── install │ ├── bindings.md │ ├── clojure-configuration.md │ ├── completion.md │ ├── doom-configuration.md │ ├── evil-configuration.md │ ├── index.md │ └── pre-install.md ├── introduction │ ├── contributing.md │ ├── repl-workflow.md │ ├── spacemacs-to-doom.md │ ├── why-doom-emacs.md │ └── writing-tips.md └── version-control │ ├── index.md │ └── magit.md ├── includes └── abbreviations.md ├── mkdocs.yml └── overrides ├── 404.html ├── main.html └── partials ├── header.html ├── palette.html └── source.html /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Codeowners 2 | 3 | # Default owner accounts for the current repository 4 | # Automatically added as a reviewr to all pull requests (not including drafts) 5 | 6 | * @practicalli-johnny 7 | -------------------------------------------------------------------------------- /.github/config/gitleaks.toml: -------------------------------------------------------------------------------- 1 | title = "gitleaks config" 2 | 3 | [allowlist] 4 | description = "global allow lists" 5 | paths = [ 6 | '''gitleaks.toml''', 7 | '''(.*?)(jpg|gif|doc|docx|zip|xls|pdf|bin|svg|socket)$''', 8 | '''(go.mod|go.sum)$''', 9 | '''gradle.lockfile''', 10 | '''node_modules''', 11 | '''package-lock.json''', 12 | '''pnpm-lock.yaml''', 13 | '''Database.refactorlog''', 14 | '''vendor''', 15 | ] 16 | 17 | [[rules]] 18 | description = "AWS Example API Key" 19 | id = "aws-example-api-key" 20 | regex = '''AKIAIOSFODNN7EXAMPLE''' 21 | keywords = [ 22 | "awstoken", 23 | ] 24 | -------------------------------------------------------------------------------- /.github/config/lychee.toml: -------------------------------------------------------------------------------- 1 | 2 | # ---------------------------------------- 3 | # Base URL or website root directory to check relative URLs. 4 | base = "https://practical.li/" 5 | 6 | # Only test links with the given schemes (e.g. https). 7 | # Omit to check links with any other scheme. 8 | # At the moment, we support http, https, file, and mailto. 9 | scheme = ["https"] 10 | 11 | # ---------------------------------------- 12 | # Exclusions 13 | 14 | # Exclude URLs and mail addresses from checking (supports regex). 15 | # exclude = ['^https://www\.linkedin\.com', '^https://web\.archive\.org/web/'] 16 | 17 | # Exclude all private IPs from checking. 18 | # Equivalent to setting `exclude_private`, `exclude_link_local`, and 19 | # `exclude_loopback` to true. 20 | exclude_all_private = false 21 | 22 | # Check mail addresses 23 | include_mail = false 24 | # ---------------------------------------- 25 | -------------------------------------------------------------------------------- /.github/config/markdown-link-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePatterns": [ 3 | { 4 | "pattern": "^http://localhost" 5 | }, 6 | { 7 | "pattern": "^mailto:*" 8 | }, 9 | { 10 | "pattern": "^#*" 11 | }, 12 | { 13 | "pattern": "^https://127.0.0.0/" 14 | } 15 | ], 16 | "timeout": "20s", 17 | "retryOn429": true, 18 | "retryCount": 5, 19 | "fallbackRetryDelay": "30s", 20 | "aliveStatusCodes": [ 21 | 200, 22 | 206 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.github/config/markdown-lint.jsonc: -------------------------------------------------------------------------------- 1 | // Example markdownlint configuration with all properties set to their default value 2 | { 3 | 4 | // Default state for all rules 5 | "default": true, 6 | 7 | // Path to configuration file to extend 8 | "extends": null, 9 | 10 | // MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time 11 | "MD001": true, 12 | 13 | // MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading 14 | "MD002": { 15 | // Heading level 16 | "level": 1 17 | }, 18 | 19 | // MD003/heading-style/header-style - Heading style 20 | "MD003": { 21 | // Heading style 22 | "style": "consistent" 23 | }, 24 | 25 | // MD004/ul-style - Unordered list style 26 | "MD004": { 27 | // List style 28 | "style": "consistent" 29 | }, 30 | 31 | // MD005/list-indent - Inconsistent indentation for list items at the same level 32 | "MD005": true, 33 | 34 | // MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line 35 | "MD006": true, 36 | 37 | // MD007/ul-indent - Unordered list indentation 38 | "MD007": { 39 | // Spaces for indent 40 | "indent": 2, 41 | // Whether to indent the first level of the list 42 | "start_indented": false, 43 | // Spaces for first level indent (when start_indented is set) 44 | "start_indent": 2 45 | }, 46 | 47 | // MD009/no-trailing-spaces - Trailing spaces 48 | "MD009": { 49 | // Spaces for line break 50 | "br_spaces": 2, 51 | // Allow spaces for empty lines in list items 52 | "list_item_empty_lines": false, 53 | // Include unnecessary breaks 54 | "strict": true 55 | }, 56 | 57 | // MD010/no-hard-tabs - Hard tabs 58 | "MD010": { 59 | // Include code blocks 60 | "code_blocks": true, 61 | // Fenced code languages to ignore 62 | "ignore_code_languages": [], 63 | // Number of spaces for each hard tab 64 | "spaces_per_tab": 1 65 | }, 66 | 67 | // MD011/no-reversed-links - Reversed link syntax 68 | "MD011": true, 69 | 70 | // MD012/no-multiple-blanks - Multiple consecutive blank lines 71 | "MD012": { 72 | // Consecutive blank lines 73 | "maximum": 2 74 | }, 75 | 76 | // MD013/line-length - Line length 77 | "MD013": { 78 | // Number of characters 79 | "line_length": 420, 80 | // Number of characters for headings 81 | "heading_line_length": 90, 82 | // Number of characters for code blocks 83 | "code_block_line_length": 420, 84 | // Include code blocks 85 | "code_blocks": true, 86 | // Include tables 87 | "tables": true, 88 | // Include headings 89 | "headings": true, 90 | // Include headings 91 | "headers": true, 92 | // Strict length checking 93 | "strict": false, 94 | // Stern length checking 95 | "stern": true 96 | }, 97 | 98 | // MD014/commands-show-output - Dollar signs used before commands without showing output 99 | "MD014": true, 100 | 101 | // MD018/no-missing-space-atx - No space after hash on atx style heading 102 | "MD018": true, 103 | 104 | // MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading 105 | "MD019": true, 106 | 107 | // MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading 108 | "MD020": true, 109 | 110 | // MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading 111 | "MD021": true, 112 | 113 | // MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines 114 | "MD022": { 115 | // Blank lines above heading 116 | "lines_above": 1, 117 | // Blank lines below heading 118 | "lines_below": 1 119 | }, 120 | 121 | // MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line 122 | "MD023": true, 123 | 124 | // MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content 125 | "MD024": { 126 | // Only check sibling headings 127 | "allow_different_nesting": false, 128 | // Only check sibling headings 129 | "siblings_only": false 130 | }, 131 | 132 | // MD025/single-title/single-h1 - Multiple top-level headings in the same document 133 | "MD025": { 134 | // Heading level 135 | "level": 1, 136 | // RegExp for matching title in front matter 137 | "front_matter_title": "^\\s*title\\s*[:=]" 138 | }, 139 | 140 | // MD026/no-trailing-punctuation - Trailing punctuation in heading 141 | "MD026": { 142 | // Punctuation characters not allowed at end of headings 143 | "punctuation": ".,;:!。,;:!" 144 | }, 145 | 146 | // MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol 147 | "MD027": true, 148 | 149 | // MD028/no-blanks-blockquote - Blank line inside blockquote 150 | "MD028": true, 151 | 152 | // MD029/ol-prefix - Ordered list item prefix 153 | "MD029": { 154 | // List style 155 | "style": "one_or_ordered" 156 | }, 157 | 158 | // MD030/list-marker-space - Spaces after list markers 159 | "MD030": { 160 | // Spaces for single-line unordered list items 161 | "ul_single": 1, 162 | // Spaces for single-line ordered list items 163 | "ol_single": 1, 164 | // Spaces for multi-line unordered list items 165 | "ul_multi": 1, 166 | // Spaces for multi-line ordered list items 167 | "ol_multi": 1 168 | }, 169 | 170 | // MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines 171 | "MD031": { 172 | // Include list items 173 | "list_items": true 174 | }, 175 | 176 | // MD032/blanks-around-lists - Lists should be surrounded by blank lines 177 | "MD032": true, 178 | 179 | // MD033/no-inline-html - Inline HTML 180 | "MD033": { 181 | // Allowed elements 182 | "allowed_elements": ["iframe", "p", "div"] 183 | }, 184 | 185 | // MD034/no-bare-urls - Bare URL used 186 | "MD034": true, 187 | 188 | // MD035/hr-style - Horizontal rule style 189 | "MD035": { 190 | // Horizontal rule style 191 | "style": "consistent" 192 | }, 193 | 194 | // MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading 195 | "MD036": { 196 | // Punctuation characters 197 | "punctuation": ".,;:!?。,;:!?" 198 | }, 199 | 200 | // MD037/no-space-in-emphasis - Spaces inside emphasis markers 201 | "MD037": true, 202 | 203 | // MD038/no-space-in-code - Spaces inside code span elements 204 | "MD038": true, 205 | 206 | // MD039/no-space-in-links - Spaces inside link text 207 | "MD039": true, 208 | 209 | // MD040/fenced-code-language - Fenced code blocks should have a language specified 210 | "MD040": { 211 | // List of languages 212 | "allowed_languages": [], 213 | // Require language only 214 | "language_only": false 215 | }, 216 | 217 | // MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading 218 | "MD041": { 219 | // Heading level 220 | "level": 1, 221 | // RegExp for matching title in front matter 222 | "front_matter_title": "^\\s*title\\s*[:=]" 223 | }, 224 | 225 | // MD042/no-empty-links - No empty links 226 | "MD042": true, 227 | 228 | // MD043/required-headings/required-headers - Required heading structure 229 | "MD043": { 230 | 231 | }, 232 | 233 | // MD044/proper-names - Proper names should have the correct capitalization 234 | "MD044": { 235 | // List of proper names 236 | "names": [], 237 | // Include code blocks 238 | "code_blocks": true, 239 | // Include HTML elements 240 | "html_elements": true 241 | }, 242 | 243 | // MD045/no-alt-text - Images should have alternate text (alt text) 244 | "MD045": true, 245 | 246 | // MD046/code-block-style - Code block style 247 | "MD046": { 248 | // Block style 249 | "style": "consistent" 250 | }, 251 | 252 | // MD047/single-trailing-newline - Files should end with a single newline character 253 | "MD047": true, 254 | 255 | // MD048/code-fence-style - Code fence style 256 | "MD048": { 257 | // Code fence style 258 | "style": "consistent" 259 | }, 260 | 261 | // MD049/emphasis-style - Emphasis style should be consistent 262 | "MD049": { 263 | // Emphasis style should be consistent 264 | "style": "consistent" 265 | }, 266 | 267 | // MD050/strong-style - Strong style should be consistent 268 | "MD050": { 269 | // Strong style should be consistent 270 | "style": "consistent" 271 | }, 272 | 273 | // MD051/link-fragments - Link fragments should be valid 274 | "MD051": true, 275 | 276 | // MD052/reference-links-images - Reference links and images should use a label that is defined 277 | "MD052": true, 278 | 279 | // MD053/link-image-reference-definitions - Link and image reference definitions should be needed 280 | "MD053": { 281 | // Ignored definitions 282 | "ignored_definitions": [ 283 | "//" 284 | ] 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /.github/config/megalinter.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configuration file for MegaLinter 3 | # 4 | # General configuration: 5 | # https://megalinter.io/latest/configuration/ 6 | # 7 | # Specific Linters: 8 | # https://megalinter.io/latest/supported-linters/ 9 | 10 | # ------------------------ 11 | # Validate all files if true 12 | # or new / edited files if false 13 | VALIDATE_ALL_CODEBASE: false 14 | 15 | # ------------------------ 16 | # Linters 17 | 18 | # Run linters in parallel 19 | PARALLEL: true 20 | 21 | # ENABLE specific linters, all other linters automatically disabled 22 | ENABLE: 23 | # - CLOJURE 24 | - CREDENTIALS 25 | - DOCKERFILE 26 | - MAKEFILE 27 | - MARKDOWN 28 | - GIT 29 | - SPELL 30 | - YAML 31 | - REPOSITORY 32 | 33 | # Linter specific configuration 34 | 35 | # CLOJURE_CLJ_KONDO_CONFIG_FILE: ".github/config/clj-kondo-ci-config.edn" 36 | # CLOJURE_CLJ_KONDO_ARGUMENTS: "--lint deps.edn" 37 | # CLOJURE_CLJ_KONDO_FILTER_REGEX_EXCLUDE: "dev|develop" 38 | # CLOJURE_CLJ_KONDO_FILTER_REGEX_EXCLUDE: "resources" 39 | 40 | # CREDENTIALS_SECRETLINT_DISABLE_ERRORS: true 41 | CREDENTIALS_SECRETLINT_CONFIG_FILE: ".github/config/secretlintrc.json" 42 | 43 | MARKDOWN_MARKDOWNLINT_CONFIG_FILE: ".github/config/markdown-lint.jsonc" 44 | MARKDOWN_MARKDOWNLINT_FILTER_REGEX_EXCLUDE: ".github/pull_request_template.md|CHANGELOG.md|README.md|GLOSSARY.md|java-17-flags.md|abbreviations.md" 45 | # MARKDOWN_MARKDOWNLINT_DISABLE_ERRORS: true 46 | MARKDOWN_MARKDOWN_LINK_CHECK_CONFIG_FILE: ".github/config/markdown-link-check.json" 47 | # MARKDOWN_MARKDOWN_LINK_CHECK_CLI_LINT_MODE: "project" 48 | # MARKDOWN_MARKDOWN_LINK_CHECK_DISABLE_ERRORS: false 49 | MARKDOWN_REMARK_LINT_DISABLE_ERRORS: true 50 | # MARKDOWN_MARKDOWN_TABLE_FORMATTER_DISABLE_ERRORS: false 51 | 52 | REPOSITORY_GITLEAKS_CONFIG_FILE: ".github/config/gitleaks.toml" 53 | REPOSITORY_TRUFFLEHOG_DISABLE_ERRORS: true # Errors only as warnings 54 | 55 | # SPELL_CSPELL_DISABLE_ERRORS: true 56 | SPELL_MISSPELL_DISABLE_ERRORS: true 57 | SPELL_LYCHEE_CONFIG_FILE: ".github/config/lychee.toml" 58 | # SPELL_LYCHEE_DISABLE_ERRORS: true # Errors are only warnings 59 | 60 | # YAML_PRETTIER_FILTER_REGEX_EXCLUDE: (docs/) 61 | # YAML_YAMLLINT_FILTER_REGEX_EXCLUDE: (docs/) 62 | 63 | # Explicitly disable linters to ensure they are never run 64 | # DISABLE: 65 | # - COPYPASTE # checks for excessive copy-pastes 66 | # - SPELL # spell checking - often creates many false positives 67 | # - CSS # 68 | 69 | # Disable linter features 70 | DISABLE_LINTERS: 71 | - YAML_PRETTIER # draconian format rules 72 | - SPELL_CSPELL # many clojure references causing false positives 73 | - YAML_YAMLLINT # vague error mesages, investigation required 74 | - REPOSITORY_GIT_DIFF # warnings about LF to CRLF 75 | - REPOSITORY_SECRETLINT # reporting errors in its own config file 76 | # - REPOSITORY_DEVSKIM # unnecessary URL TLS checks 77 | - REPOSITORY_CHECKOV # fails on root user in Dockerfile 78 | - REPOSITORY_SECRETLINT 79 | 80 | # Ignore all errors and return without error status 81 | # DISABLE_ERRORS: true 82 | 83 | # ------------------------ 84 | 85 | # ------------------------ 86 | # Reporting 87 | 88 | # Activate sources reporter 89 | UPDATED_SOURCES_REPORTER: false 90 | 91 | # Show Linter timings in summary table at end of run 92 | SHOW_ELAPSED_TIME: true 93 | 94 | # Upload reports to file.io 95 | FILEIO_REPORTER: false 96 | # ------------------------ 97 | 98 | # ------------------------ 99 | # Over-ride errors 100 | 101 | # detect errors but do not block CI passing 102 | # DISABLE_ERRORS: true 103 | # ------------------------ 104 | -------------------------------------------------------------------------------- /.github/config/secretlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": [ 3 | { 4 | "id": "@secretlint/secretlint-rule-basicauth", 5 | "options": { 6 | "allows": [ 7 | "hostname.domain.com", 8 | "jdbc:postgresql://:port/?user=&password=", 9 | "postgres://postgres://username:password@hostname.domain.com:1234/database-name" 10 | ] 11 | } 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | :memo: Description 2 | 3 | 4 | :white_check_mark: Checklist 5 | 6 | - [ ] Commits should be cryptographically signed (SSH or GPG) 7 | 8 | 9 | ## Practicalli Guidelines 10 | 11 | Please follow these guidelines when submitting a pull request 12 | 13 | - refer to all relevant issues, using `#` followed by the issue number (or paste full link to the issue) 14 | - PR should contain the smallest possible change 15 | - PR should contain a very specific change 16 | - PR should contain only a single commit (squash your commits locally if required) 17 | - Avoid multiple changes across multiple files (raise an issue so we can discuss) 18 | - Avoid a long list of spelling or grammar corrections. These take too long to review and cherry pick. 19 | 20 | ## Submitting articles 21 | 22 | [Create an issue using the article template](https://github.com/practicalli/blog-content/issues/new?assignees=&labels=article&template=article.md&title=Suggested+article+title), 23 | providing as much detail as possible. 24 | 25 | ## Website design 26 | 27 | Suggestions about website design changes are most welcome, especially in terms of usability and accessibility. 28 | 29 | Please raise an issue so we can discuss changes first, especially changes related to aesthetics. 30 | 31 | ## Review process 32 | 33 | All pull requests are reviewed by @practicalli-johnny and feedback provided, usually the same day but please be patient. 34 | -------------------------------------------------------------------------------- /.github/workflows/changelog-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Check CHANGELOG.md file updated for every pull request 3 | 4 | name: Changelog Check 5 | on: 6 | pull_request: 7 | paths-ignore: 8 | - "README.md" 9 | types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] 10 | 11 | jobs: 12 | changelog: 13 | name: Changelog Update Check 14 | runs-on: ubuntu-latest 15 | steps: 16 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 17 | - run: echo "🐧 Job running on ${{ runner.os }} server" 18 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 19 | 20 | # Git Checkout 21 | - name: Checkout Code 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | sparse-checkout: | 26 | docs 27 | overrides 28 | .github 29 | CHANGELOG.md 30 | - run: echo "🐙 Sparse Checkout of ${{ github.repository }} repository to the CI runner." 31 | 32 | # Changelog Enforcer 33 | - name: Changelog Enforcer 34 | uses: dangoslen/changelog-enforcer@v3 35 | with: 36 | changeLogPath: "CHANGELOG.md" 37 | skipLabels: "skip-changelog-check" 38 | 39 | # Summary and status 40 | - run: echo "🎨 Changelog Enforcer quality checks completed" 41 | - run: echo "🍏 Job status is ${{ job.status }}." 42 | -------------------------------------------------------------------------------- /.github/workflows/megalinter.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # MegaLinter GitHub Action configuration file 3 | # More info at https://megalinter.github.io 4 | # All variables described in https://megalinter.github.io/configuration/ 5 | 6 | name: MegaLinter 7 | on: 8 | workflow_dispatch: 9 | pull_request: 10 | branches: [main] 11 | push: 12 | branches: [main] 13 | 14 | # Run Linters in parallel 15 | # Cancel running job if new job is triggered 16 | concurrency: 17 | group: "${{ github.ref }}-${{ github.workflow }}" 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | megalinter: 22 | name: MegaLinter 23 | runs-on: ubuntu-latest 24 | steps: 25 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 26 | - run: echo "🐧 Job running on ${{ runner.os }} server" 27 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 28 | 29 | # Git Checkout 30 | - name: Checkout Code 31 | uses: actions/checkout@v4 32 | with: 33 | fetch-depth: 0 34 | sparse-checkout: | 35 | docs 36 | overrides 37 | .github 38 | - run: echo "🐙 Sparse Checkout of ${{ github.repository }} repository to the CI runner." 39 | 40 | # MegaLinter Configuration 41 | - name: MegaLinter Run 42 | id: ml 43 | ## latest release of major version 44 | uses: oxsecurity/megalinter/flavors/documentation@v7 45 | env: 46 | # ADD CUSTOM ENV VARIABLES OR DEFINE IN MEGALINTER_CONFIG file 47 | MEGALINTER_CONFIG: .github/config/megalinter.yaml 48 | 49 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" # report individual linter status 50 | # Validate all source when push on main, else just the git diff with live. 51 | VALIDATE_ALL_CODEBASE: >- 52 | ${{ github.event_name == 'push' && github.ref == 'refs/heads/main'}} 53 | 54 | # Upload MegaLinter artifacts 55 | - name: Archive production artifacts 56 | if: ${{ success() }} || ${{ failure() }} 57 | uses: actions/upload-artifact@v4 58 | with: 59 | name: MegaLinter reports 60 | path: | 61 | megalinter-reports 62 | mega-linter.log 63 | 64 | # Summary and status 65 | - run: echo "🎨 MegaLinter quality checks completed" 66 | - run: echo "🍏 Job status is ${{ job.status }}." 67 | -------------------------------------------------------------------------------- /.github/workflows/publish-book.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Publish Book 3 | on: 4 | # Manually trigger workflow 5 | workflow_dispatch: 6 | 7 | # Run work flow conditional on linter workflow success 8 | workflow_run: 9 | workflows: 10 | - "MegaLinter" 11 | paths: 12 | - "docs/**" 13 | - "includes/**" 14 | - "overrides/**" 15 | - "mkdocs.yaml" 16 | branches: 17 | - main 18 | types: 19 | - completed 20 | 21 | permissions: 22 | contents: write 23 | 24 | jobs: 25 | publish-book: 26 | name: MkDocs Publish 27 | runs-on: ubuntu-latest 28 | steps: 29 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 30 | - run: echo "🐧 Job running on ${{ runner.os }} server" 31 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 32 | 33 | - name: Checkout Code 34 | uses: actions/checkout@v4 35 | with: 36 | fetch-depth: 0 37 | sparse-checkout: | 38 | docs 39 | overrides 40 | - run: echo "🐙 ${{ github.repository }} repository sparse-checkout to the CI runner." 41 | 42 | - name: Setup Python 43 | uses: actions/setup-python@v5 44 | with: 45 | python-version: 3.x 46 | 47 | - name: Cache 48 | uses: actions/cache@v4 49 | with: 50 | key: ${{ github.ref }} 51 | path: .cache 52 | 53 | - run: pip install mkdocs-material mkdocs-callouts mkdocs-glightbox mkdocs-git-revision-date-localized-plugin mkdocs-redirects pillow cairosvg 54 | - run: mkdocs gh-deploy --force 55 | - run: echo "🐙 ." 56 | 57 | # Summary and status 58 | - run: echo "🎨 MkDocs Publish Book workflow completed" 59 | - run: echo "🍏 Job status is ${{ job.status }}." 60 | -------------------------------------------------------------------------------- /.github/workflows/scheduled-stale-check.yaml: -------------------------------------------------------------------------------- 1 | # ---------------------------------------- 2 | # Scheduled stale issue & pull request check 3 | # 4 | # Adds 'stale' label after a set piece of time, 5 | # then closes stale issues & pull requests a short period after 6 | # 7 | # Using "Close Stale Issues" action 8 | # https://github.com/marketplace/actions/close-stale-issues 9 | # ---------------------------------------- 10 | 11 | name: 'Scheduled stale check' 12 | on: 13 | workflow_dispatch: 14 | schedule: 15 | - cron: "0 1 1 * *" # at 01:00 on first day of month 16 | 17 | jobs: 18 | stale: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 22 | - run: echo "🐧 Job running on ${{ runner.os }} server" 23 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 24 | 25 | - uses: actions/stale@v9 26 | with: 27 | stale-issue-message: 'After 30 days with no activity, the issue was automatically marked stale. Remove stale label or add a comment to prevent the issue being closed in 5 days.' 28 | stale-pr-message: 'After 45 days with no activity, the Pull Request was automatically marked stale. Remove stale label or comment to prevent the PR being closed in 10 days.' 29 | close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.' 30 | close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.' 31 | days-before-issue-stale: 30 32 | days-before-pr-stale: 45 33 | days-before-issue-close: 5 34 | days-before-pr-close: 10 35 | start-date: '2025-04-05T00:00:00Z' # only affect issues/PRs from date created (ISO 8601 or RFC 2822 format) 36 | any-of-labels: 'future,keep' # labels to keep 37 | exempt-issue-assignees: 'practicalli-johnny' 38 | exempt-pr-assignees: 'practicalli-johnny' 39 | 40 | # Summary 41 | - run: echo "🎨 Issues & Pull Request checked with actions/stale" 42 | - run: echo "🍏 Job status is ${{ job.status }}." 43 | -------------------------------------------------------------------------------- /.github/workflows/scheduled-version-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------ 3 | # Scheduled check of versions 4 | # - use as non-urgent report on versions 5 | # - Uses POSIX Cron syntax 6 | # - Minute [0,59] 7 | # - Hour [0,23] 8 | # - Day of the month [1,31] 9 | # - Month of the year [1,12] 10 | # - Day of the week ([0,6] with 0=Sunday) 11 | # 12 | # Using liquidz/anta to check: 13 | # - GitHub workflows 14 | # - deps.edn 15 | # ------------------------------------------ 16 | 17 | name: "Scheduled Version Check" 18 | on: 19 | schedule: 20 | # - cron: "0 4 * * *" # at 04:04:04 ever day 21 | # - cron: "0 4 * * 5" # at 04:04:04 ever Friday 22 | - cron: "0 4 1 * *" # at 04:04:04 on first day of month 23 | workflow_dispatch: # Run manually via GitHub Actions Workflow page 24 | 25 | jobs: 26 | scheduled-version-check: 27 | name: "Scheduled Version Check" 28 | runs-on: ubuntu-latest 29 | steps: 30 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 31 | - run: echo "🐧 Job running on ${{ runner.os }} server" 32 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 33 | 34 | - name: Checkout Code 35 | uses: actions/checkout@v4 36 | with: 37 | fetch-depth: 0 38 | sparse-checkout: | 39 | .github 40 | - run: echo "🐙 ${{ github.repository }} repository sparse-checkout to the CI runner." 41 | - name: "Antq Check versions" 42 | uses: liquidz/antq-action@main 43 | with: 44 | excludes: "" 45 | skips: "boot clojure-cli pom shadow-cljs leiningen" 46 | 47 | # Summary 48 | - run: echo "🎨 library versions checked with liquidz/antq" 49 | - run: echo "🍏 Job status is ${{ job.status }}." 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Exclude all files from root directory 2 | /* 3 | 4 | # ------------------------ 5 | # Common project files 6 | !CHANGELOG.md 7 | !README.md 8 | !LICENSE 9 | 10 | # ------------------------ 11 | # Include MkDocs files 12 | !docs/ 13 | !includes/ 14 | !overrides/ 15 | !mkdocs.yml 16 | 17 | # ------------------------ 18 | # Project automation 19 | !Makefile 20 | 21 | # ------------------------ 22 | # Version Control 23 | !.gitignore 24 | !.github/ 25 | 26 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Unreleased 2 | 3 | ## Added 4 | 5 | ## Changed 6 | - dev: ci scheduled stale issue & pr check (monthly) 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------ 2 | # Practicalli: Makefile 3 | # 4 | # Consistent set of targets to support local book development 5 | # ------------------------------------------ 6 | 7 | # .PHONY: ensures target used rather than matching file name 8 | # https://makefiletutorial.com/#phony 9 | .PHONY: all clean docs lint pre-commit-check test 10 | 11 | # ------- Makefile Variables --------- # 12 | # run help if no target specified 13 | .DEFAULT_GOAL := help 14 | 15 | # Column the target description is printed from 16 | HELP-DESCRIPTION-SPACING := 24 17 | 18 | # Tool Commands 19 | MEGALINTER_RUNNER := npx mega-linter-runner --flavor documentation --env "'MEGALINTER_CONFIG=.github/config/megalinter.yaml'" --env "'VALIDATE_ALL_CODEBASE=true'" --remove-container 20 | MKDOCS_SERVER := mkdocs serve --dev-addr localhost:7777 21 | 22 | # Makefile file and directory name wildcard 23 | EDN-FILES := $(wildcard *.edn) 24 | # ------------------------------------ # 25 | 26 | # ------ Quality Checks ------------ # 27 | pre-commit-check: lint 28 | 29 | lint: ## Run MegaLinter with custom configuration (node.js required) 30 | $(info --------- MegaLinter Runner ---------) 31 | $(MEGALINTER_RUNNER) 32 | 33 | lint-fix: ## Run MegaLinter with custom configuration (node.js required) 34 | $(info --------- MegaLinter Runner ---------) 35 | $(MEGALINTER_RUNNER) --fix 36 | 37 | lint-clean: ## Clean MegaLinter report information 38 | $(info --------- MegaLinter Clean Reports ---------) 39 | - rm -rf ./megalinter-reports 40 | # ------------------------------------ # 41 | 42 | # --- Documentation Generation ------ # 43 | docs: ## Build and run mkdocs in local server 44 | $(info --------- Mkdocs Local Server ---------) 45 | $(MKDOCS_SERVER) 46 | 47 | docs-changed: ## Build only changed files and run mkdocs in local server 48 | $(info --------- Mkdocs Local Server ---------) 49 | $(MKDOCS_SERVER) --dirtyreload 50 | 51 | docs-build: ## Build mkdocs 52 | $(info --------- Mkdocs Local Server ---------) 53 | mkdocs build 54 | # ------------------------------------ # 55 | 56 | # ------------ Help ------------------ # 57 | # Source: https://nedbatchelder.com/blog/201804/makefile_help_target.html 58 | 59 | help: ## Describe available tasks in Makefile 60 | @grep '^[a-zA-Z]' $(MAKEFILE_LIST) | \ 61 | sort | \ 62 | awk -F ':.*?## ' 'NF==2 {printf "\033[36m %-$(HELP-DESCRIPTION-SPACING)s\033[0m %s\n", $$1, $$2}' 63 | # ------------------------------------ # 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Practicalli Doom Emacs 2 | 3 | ```none 4 | ██████╗ ██████╗ █████╗ ██████╗████████╗██╗ ██████╗ █████╗ ██╗ ██╗ ██╗ 5 | ██╔══██╗██╔══██╗██╔══██╗██╔════╝╚══██╔══╝██║██╔════╝██╔══██╗██║ ██║ ██║ 6 | ██████╔╝██████╔╝███████║██║ ██║ ██║██║ ███████║██║ ██║ ██║ 7 | ██╔═══╝ ██╔══██╗██╔══██║██║ ██║ ██║██║ ██╔══██║██║ ██║ ██║ 8 | ██║ ██║ ██║██║ ██║╚██████╗ ██║ ██║╚██████╗██║ ██║███████╗███████╗██║ 9 | ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ 10 | ``` 11 | 12 | ## Project on hold 13 | 14 | Practicalli is not actively developing this configuration, although it should be useable with current versions of Doom Emacs and Emacs 28 onward. 15 | 16 | 17 | ## Book status 18 | 19 | [![MegaLinter](https://github.com/practicalli/doom-emacs/actions/workflows/megalinter.yml/badge.svg)](https://github.com/practicalli/doom-emacs/actions/workflows/megalinter.yml) 20 | [![Publish Book](https://github.com/practicalli/doom-emacs/actions/workflows/publish-book.yaml/badge.svg)](https://github.com/practicalli/doom-emacs/actions/workflows/publish-book.yaml) 21 | [![pages-build-deployment](https://github.com/practicalli/doom-emacs/actions/workflows/pages/pages-build-deployment/badge.svg)](https://github.com/practicalli/doom-emacs/actions/workflows/pages/pages-build-deployment) 22 | 23 | ![Ideas & issues](https://img.shields.io/github/issues/practicalli/doom-emacs?label=content%20ideas&logo=github) 24 | ![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/practicalli/doom-emacs?label=pull%20requests&logo=github) 25 | 26 | ![GitHub commit activity](https://img.shields.io/github/commit-activity/y/practicalli/doom-emacs?label=commits&logo=github) 27 | 28 | 29 | ## Creative commons license 30 | 31 |
32 | Creative Commons License 33 | This work is licensed under a Creative Commons Attribution 4.0 ShareAlike License (including images & stylesheets). 34 |
35 | 36 | ## Overview 37 | 38 | The Practicalli Doom Emacs provides practical guides to software development tasks, using predominantly the Clojure and ClojureScript languages. Most of the editing techniques and tools are applicable to any editing tasks. 39 | 40 | Doom Emacs is an open source project to provide configuration to add 150+ packages to Emacs, without having to writing a lot of common configuration code. 41 | 42 | [![Discuss this guide on #practicalli channel of the Clojurians Slack community](images/practicalli-slack-channel.png)](https://clojurians.slack.com/messages/practicalli). 43 | 44 | [Create a free Clojurians Slack community account](http://clojurians.net/). 45 | 46 | This book will cover the following topics: 47 | * Emacs basics, common commands and tools 48 | * Powerful editing and refactor tools (iedt, narrowing, helm-ag, multiple cursors, visual undo) 49 | * Adding and enhancing the Clojure layer 50 | * Running the REPL, evaluating code, inspecting data, debug, reloaded workflow 51 | * Running tests & test reports 52 | * Structural editing (smartparens/evil-cleverparens) 53 | * Clojure docs, auto-completion, snippets 54 | * Clojurescript development, figwheel-main and reagent 55 | * Org-mode for project documentation, literate programming & presentations 56 | 57 | ## Contributing 58 | 59 | Issues and pull requests are most welcome. Please detail issues as much as you can. Pull requests are simpler to work with when they are specific to a page or at most a section. The smaller the change the quicker it is to review and merge. 60 | 61 | Please [see the detailed contributing section of the book](contributing.html) before raising an issue or pull request 62 | 63 | 64 | * [Current Issues](https://github.com/practicalli/doom-emacs/issues) 65 | * [Current pull requests](https://github.com/practicalli/doom-emacs/pulls) 66 | 67 | [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config/) GitHub repository contains the Practicalli Doom Emacs configuration used in this guide and issues and pull requests can also be made there. 68 | 69 | ## Contributing 70 | 71 | Please [read the contributing section of the book](https://practical.li/doom-emacs/introduction/contributing/) page before raising an issue or pull request 72 | 73 | By submitting content ideas and corrections you are agreeing they can be used in this workshop under the [Creative Commons Attribution ShareAlike 4.0 International license](https://creativecommons.org/licenses/by-sa/4.0/). Attribution will be detailed via [GitHub contributors](https://github.com/practicalli/neovim/graphs/contributors). 74 | 75 | 76 | ## Sponsor Practicalli 77 | 78 | [![Sponsor Practicalli via GitHub](https://raw.githubusercontent.com/practicalli/graphic-design/live/buttons/practicalli-github-sponsors-button.png)](https://github.com/sponsors/practicalli-johnny/) 79 | 80 | All sponsorship funds are used to support the continued development of [Practicalli series of books and videos](https://practical.li/), although most work is done at personal cost and time. 81 | 82 | Thanks to [Cognitect](https://www.cognitect.com/), [Nubank](https://nubank.com.br/) and a wide range of other [sponsors](https://github.com/sponsors/practicalli-johnny#sponsors) for your continued support 83 | 84 | 85 | ## GitHub Actions 86 | 87 | The megalinter GitHub actions will run when a pull request is created,checking basic markdown syntax. 88 | 89 | A review of the change will be carried out by the Practicalli team and the PR merged if the change is acceptable. 90 | 91 | The Publish Book GitHub action will run when PR's are merged into main (or the Practicalli team pushes changes to the default branch). 92 | 93 | Publish book workflow installs Material for MkDocs version 9 94 | 95 | 96 | ## Local development 97 | 98 | Install mkdocs version 9 using the Python pip package manager 99 | 100 | ```bash 101 | pip install mkdocs-material=="9.*" 102 | ``` 103 | 104 | Install the plugins used by the Practicalli site using Pip (these are also installed in the GitHub Action workflow) 105 | 106 | ```bash 107 | pip3 install mkdocs-material mkdocs-callouts mkdocs-glightbox mkdocs-git-revision-date-localized-plugin mkdocs-redirects pillow cairosvg 108 | ``` 109 | 110 | > pillow and cairosvg python packages are required for [Social Cards](https://squidfunk.github.io/mkdocs-material/setup/setting-up-social-cards/) 111 | 112 | Fork the GitHub repository and clone that fork to your computer, 113 | 114 | ```bash 115 | git clone https://github.com//.git 116 | 117 | ``` 118 | 119 | Run a local server from the root of the cloned project 120 | 121 | ```bash 122 | mkdocs serve 123 | ``` 124 | 125 | The website will open at 126 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/doom-emacs/59340d1190bff2a804a3733a9a5f3323d686e21b/docs/.nojekyll -------------------------------------------------------------------------------- /docs/assets/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/doom-emacs/59340d1190bff2a804a3733a9a5f3323d686e21b/docs/assets/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/assets/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/doom-emacs/59340d1190bff2a804a3733a9a5f3323d686e21b/docs/assets/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/assets/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/doom-emacs/59340d1190bff2a804a3733a9a5f3323d686e21b/docs/assets/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/assets/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/doom-emacs/59340d1190bff2a804a3733a9a5f3323d686e21b/docs/assets/favicon-16x16.png -------------------------------------------------------------------------------- /docs/assets/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/doom-emacs/59340d1190bff2a804a3733a9a5f3323d686e21b/docs/assets/favicon-32x32.png -------------------------------------------------------------------------------- /docs/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/doom-emacs/59340d1190bff2a804a3733a9a5f3323d686e21b/docs/assets/favicon.ico -------------------------------------------------------------------------------- /docs/assets/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | image/svg+xml 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | I 19 | P 20 | 9 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/assets/images/practicalli-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/doom-emacs/59340d1190bff2a804a3733a9a5f3323d686e21b/docs/assets/images/practicalli-logo.png -------------------------------------------------------------------------------- /docs/assets/images/social/README.md: -------------------------------------------------------------------------------- 1 | # Social Cards 2 | 3 | Social Cards are visual previews of the website that are included when sending links via social media platforms. 4 | 5 | Material for MkDocs is [configured to generate beautiful social cards automatically](https://squidfunk.github.io/mkdocs-material/setup/setting-up-social-cards/), using the colors, fonts and logos defined in `mkdocs.yml` 6 | 7 | Generated images are stored in this directory. 8 | -------------------------------------------------------------------------------- /docs/assets/practicalli-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | image/svg+xml 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | I 31 | P 32 | 9 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/assets/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | [data-md-color-scheme="default"] { 2 | --md-default-bg-color: hsla(208, 100%, 96%, 0.94); 3 | --md-code-bg-color: hsla(208, 80%, 88%, 0.64); 4 | --md-code-hl-color: hsla(208, 88%, 80%, 0.92); 5 | --md-admonition-bg-color: hsla(208, 80%, 92%, 0.92); 6 | --md-typeset-kbd-color: hsla(208, 100%, 98%, 0.98); 7 | } 8 | -------------------------------------------------------------------------------- /docs/basics/evil-editing.md: -------------------------------------------------------------------------------- 1 | # Evil Editing 2 | 3 | Evil provides vim-style multiple editing states, greatly increasing key binding reuse and minimising the need for simultaneous key presses. 4 | 5 | Doom Emacs provides Evil editing states 6 | 7 | * **normal** - for manipulating and navigating existing text (default state) 8 | * **insert** - for writing new text 9 | * **visual** - for selecting blocks of text 10 | 11 | !!! HINT "Normal state by default" 12 | Evil normal state should be used most of the time, unless writing lots of new code or text. 13 | 14 | ## Normal state 15 | 16 | ++"j"++,++"k"++,++"h"++,++"l"++ to navigate text, use with ++ctrl++ to navigate menus, with ++spc++ ++"w"++ to navigate windows 17 | 18 | ## Insert state 19 | 20 | Insert new text (or ++delete++), e.g. when writing new code or documentation 21 | 22 | The most common keys to enter insert mode from normal mode are: 23 | 24 | ++"i"++ to insert before the cursor, ++"a"++ to append after the cursor 25 | 26 | ++"o"++ to insert an new line below the cursor, ++"O"++ to insert a new line after the cursor 27 | 28 | ++"f"++ ++"d"++ or ++esc++ to leave insert mode and return to normal mode. 29 | 30 | 31 | ## Visual state 32 | 33 | Select characters, words, lines and regions with visual select. The background changes color to visually indicate which text is selected 34 | 35 | ++"v"++ to visually select a region and run commands on the text in that region. Selection can be done with the navigation keys or motions objects such as word `w` and locations such as end of line `$`. 36 | 37 | ++shift+"v"++ to visually select by line. ++"v"++ ++"g"++ ++"g"++ to select from current position to top of file, ++"v"++ ++"G"++ to select from current point to end of file. 38 | 39 | ++ctrl+"v"++ to select a region using the `hjkl` navigation keys, e.g. to select table data. 40 | 41 | ++"g"++ ++"c"++ on a selected region will add comment characters to the start of each line in the region 42 | 43 | ++"v"++ ++tilde++ toggles the case of the selected text (upper/lower case) 44 | 45 | `o` to toggle between the left and right side of selection 46 | 47 | 48 | ## Evil surround 49 | 50 | ++"S"++ to surround the current character with the given character, i.e. ++double-quotes++ 51 | 52 | ++"v"++ ++s++ followed by a character will surrond the visually selected text with that character. 53 | 54 | 55 | ## Learn Vim-style editing 56 | 57 | Vim-style editing is arguably the most effective way to work with text, supporting changes as much through text manipulation as editing text. Once practised, vim-style editing is far faster than uni-mode editing. 58 | 59 | The recommended way to learn vim style editing is to practice and ideally use it for everything you do. 60 | 61 | ++spc++ ++"h"++ ++t++ ++"v"++ starts the build in Vim tutorial. This provides the basic movement of vim and provides an interactive way to practice your skills 62 | 63 | To help make Vim style editing become a sub-conscious act you should [learn to speak Evil](../vim-style/speaking-evil.md) 64 | 65 | [Vim Adventures](https://vim-adventures.com/){target=_blank} is a web-based game that is an alternative to practising Vim. 66 | 67 | 68 | ### Learning resource for Evil 69 | 70 | * [Graphical Cheatsheet Tutorial](http://www.viemu.com/a_vi_vim_graphical_cheat_sheet_tutorial.html){target=_blank} 71 | * [Vim quick reference guide](http://vimhelp.appspot.com/quickref.txt.html){target=_blank} 72 | * [Vim Casts](http://vimcasts.org/){target=_blank} 73 | 74 |

75 | 76 |

77 | -------------------------------------------------------------------------------- /docs/basics/evil-tools.md: -------------------------------------------------------------------------------- 1 | # Evil Editing tools 2 | 3 | 4 | * Multiedit - multiple match and replace 5 | * Multiple cursors - add cursors and edit in paralell 6 | 7 | 8 | ## Multiedit 9 | 10 | 11 | 12 | 13 | ## Multiple cursors 14 | 15 | Multiple cursors is most useful where the same changes are required in multiple lines, especially where those lines may be similar in structure but not idential. 16 | 17 | Line based Evil commands work with multiple cursors, e.g. ++dollar++ to move to end of line, ++"f"++ / ++"F"++ to move forward / backward to a character, 18 | 19 | ++"g"++ ++"z"++ menu for mutliple cursor menu 20 | 21 | When changes are vertically aligined, create multiple cursors with vim-style movements: 22 | 23 | ++2++ ++4++ ++"g"++ ++"z"++ ++i++ adds a cursor to the next 24 lines 24 | 25 | Changes in more random positions benefit from creating 'frozen' cursors in any position that only take key input once switched to mirroring or activated by Evil Insert mode 26 | 27 | ++"g"++ ++"z"++ ++"z"++ toggle new (frozen) cursors at point. Frozen cursors stay in position until mirroring switched on or switching to insert mode 28 | 29 | ++"g"++ ++"z"++ ++"t"++ toggle mirroring on and off 30 | 31 | With visual select: 32 | 33 | ++"g"++ ++"z"++ ++i++ to create curors at start of visual selection region 34 | 35 | ++"g"++ ++"z"++ ++a++ to create curors at end (append) of visual selection region 36 | 37 | Remove multiple cursors: 38 | 39 | ++"g"++ ++"z"++ ++"q"++ to cancel all cursors 40 | -------------------------------------------------------------------------------- /docs/basics/getting-help.md: -------------------------------------------------------------------------------- 1 | # Getting Help with Doom Emacs 2 | 3 | The main places to get help with Doom Emacs seem to be: 4 | 5 | * Doom Emacs built-in docs - sparse but useful when present 6 | * Discorse - community frequently asked questions - search for previous discussions 7 | * Discord - chat based help from the community 8 | 9 | 10 | ## Doom Emacs Built-in docs 11 | 12 | ++spc++ ++"h"++ ++"d"++ ++"h"++ opens a list of available documentation, ++ctrl++ ++"j"++ / ++"k"++ to scroll through the list or type a pattern to narrow the list. 13 | 14 | ++enter++ opens the highlighted documentation in a new buffer 15 | 16 | > Not everything is documentation in detail in Doom, but the built-in documentation is a good starting place. 17 | 18 | 19 | ## Doom Discourse 20 | 21 | [Doom Discourse website](https://discourse.doomemacs.org/) provides guides and tutorials for using Doom Emacs. 22 | 23 | Questions can also be asked on Discourse in the `#doom-help` channel, althought Practicalli had more success using Discord for questions. 24 | 25 | !!! TIP "Use Discourse as Extended Docs" 26 | Search discourse for previous discussions which can often fill in for missing Doom documentation. If the topic is not covered in Doom Discourse then ask questions in Discord. 27 | 28 | 29 | ## Discord 30 | 31 | [Doom Discord community](https://discord.com/channels/406534637242810369/1019657860361224202) is a chat website that can also be accessed via the Discord application. 32 | 33 | Discord was found to be most useful for asking questions once the built-in docs and Doom Discourse had been searched. 34 | 35 | 36 | ## Clojurians Slack 37 | 38 | The `#doom-emacs` channel on the Clojurians Slack is similar to Discord, although with far fewer members. Unless its a Clojure & Doom specific question then probably better to ask on Discord. 39 | 40 | 41 | ## Stack Overflow 42 | 43 | Stack Overflow has an `emacs` tag, and a more specific [`doom` tag with far fewer questions](https://stackoverflow.com/questions/tagged/emacs) (but perhaps more relevant) nothing specific for Doom Emacs. 44 | 45 | Search using the emacs tag including Doom in the patter to help find relevant articles 46 | 47 | There are a [large number of general Emacs questions under the emacs tag](https://stackoverflow.com/questions/tagged/emacs). 48 | -------------------------------------------------------------------------------- /docs/basics/index.md: -------------------------------------------------------------------------------- 1 | # Basic usage 2 | 3 | [Projects](projects.md){.md-button} 4 | [Workspaces](workspaces.md){.md-button} 5 | [Evil Tools](evil-tools.md){.md-button} 6 | 7 | 8 | ## Command Menu 9 | 10 | ++spc++ is the leader key that opens the main Doom Emacs command menu 11 | 12 | ++comma++ is the localleader key that opens a context specific menu, with commands for the current major mode (clojure, markdown, yaml, etc.) 13 | 14 | !!! HINT "Keycast shows key bindings and commands" 15 | ++spc++ ++"t"++ ++"k"++ toggles keycast mode which displays the key bindings and associated command in the mode-line 16 | 17 | 18 | ## Line numbers 19 | 20 | ++spc++ ++"t"++ ++"l"++ toggles consecutive line numbers 21 | 22 | 23 | ## Theme 24 | 25 | ++spc++ ++"h"++ ++"t"++ lists the theme names available, select a theme name to change the theme instantly. 26 | 27 | !!! NOTE "Confirm Theme should run elisp code" 28 | Doom prompts to confirm if elisp should be run if included in a theme. A theme can be marked as safe, so further confirmation is not required. 29 | 30 | 31 | ## Zoom Frame and text 32 | 33 | ++spc++ ++"t"++ ++"b"++ to toggle Doom Big mode which applies `doom-big-font` to text across all buffers, essentailly scaling the Emacs frame. 34 | 35 | Leaving Doom Big mode resets the text size to `doom-font`. This is the recommended approach to scaling Doom Emacs. 36 | 37 | ??? INFO "Set Doom font sizes in config.el" 38 | Set a standard size font for general use and a big font for demos, screencasts, pairing, etc. The following configuration is used in [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank} 39 | 40 | ```emacs title="~/.config/doom/config.el" 41 | ;; See 'C-h v doom-font' for documentation and more examples of what they accept. For example: 42 | ;;(setq doom-font (font-spec :family "Fira Code" :size 12 :weight 'semi-light) 43 | ;; doom-variable-pitch-font (font-spec :family "Fira Sans" :size 13)) 44 | 45 | (setq doom-font (font-spec :family "Fira Code" :size 14) 46 | doom-big-font (font-spec :family "Fira Code" :size 24) 47 | doom-variable-pitch-font (font-spec :family "Ubuntu" :size 16)) 48 | ``` 49 | 50 | Alternatively the text in a specific buffer can be scalled, although this does not scale the mini-buffer and its affects are not applied to any other buffer. 51 | 52 | ++ctrl+"x"++ ++ctrl+plus++ to increase the size of text in the current buffer 53 | 54 | ++ctrl+"x"++ ++ctrl+minus++ to decrease the size of text in the current buffer 55 | 56 | ++ctrl+"x"++ ++ctrl+0++ to reest the size of text in the current buffer to the default `doom-font` size 57 | 58 | 59 | ## Files 60 | 61 | ++spc++ ++"f"++ ++"f"++ to list files in current directory or create relative files and directories 62 | 63 | ++spc++ ++"p"++ ++"f"++ to list files in current project, providing a quick way to open any file in the project by filtering the list 64 | 65 | !!! HINT "Create files and directories" 66 | ++spc++ ++"f"++ ++"f"++ and typing a path and file will create the file and intermediate directories if they do not exist 67 | 68 | 69 | ## Format tools 70 | 71 | ++comma++ ++double-quote++ is typically the default format menu if available for a language major mode, calling tools specific to each language. 72 | 73 | Automatic formatting whilst typing is supported when a language module includes the `+lsp` feature and a suitable LSP language server has been installed. 74 | 75 | [LSP Language Server install](/doom-emacs/install/#language-servers){ .md-button } 76 | 77 | ??? INFO "Doom format module to be redeveloped" 78 | LSP language servers are the most effective way to support formatting in Doom Emacs, as the Doom Emacs Format module is to be rewritten. 79 | 80 | 81 | ## Whitespace cleanup 82 | 83 | ++spc++ ++"c"++ ++"w"++ to remove whitespace from end of lines and additional blank lines from the end of the file. 84 | 85 | `ws-buttler-mode` is enabled by default and removes additional whitespace from changed lines. 86 | 87 | ??? HINT "Markdown exclued from ws-buttler" 88 | ws-buttler excludes markdow mode from ws-buttler mode (there is a rare case where additional whitespace at the end of lines are used as a visual break) 89 | 90 | [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank} includes Markdown mode in ws-buttler 91 | ```emacs title=".config/doom/config.el" 92 | ;; Delete whitespace on save, including in markdow-mode 93 | (setq ws-butler-global-exempt-modes '(special-mode comint-mode term-mode eshell-mode diff-mode)) 94 | ``` 95 | 96 | ## Format Source Code 97 | 98 | Formats source code according to the programming language format: 99 | 100 | ++equal++ ++equal++ formats the current line 101 | 102 | ++equal++ formats a selected region 103 | 104 | ++greater-than++ ++greater-than++ indents the current line 105 | 106 | ++greater-than++ indents the selected region 107 | 108 | 109 | ## References 110 | 111 | * [Keybind reference sheet](https://discourse.doomemacs.org/t/keybind-reference-sheet/49) - doom discourse 112 | * [Doom Getting Started Guide](https://github.com/doomemacs/doomemacs/blob/master/docs/getting_started.org) 113 | -------------------------------------------------------------------------------- /docs/basics/projects.md: -------------------------------------------------------------------------------- 1 | # Working with Projects 2 | 3 | ++spc++ ++"p"++ ++"a"++ to add a new project to Doom, selecting the directory path for the root of the project. 4 | 5 | ++spc++ ++"p"++ ++"p"++ to switch to a project other than the current, list shows all other projects except current project. 6 | 7 | A project is automatically assigned a [workspace](workspaces.md) when opened. ++spc++ ++tab++ ++"r"++ to rename the workspace 8 | 9 | ++spc++ ++"l"++ ++"l"++ to list all current workspaces and select a different workspace. 10 | 11 | ++spc++ ++back-tick++ to switch to previous buffer 12 | 13 | ++spc++ ++tab++ ++back-tick++ to switch to previous workspace 14 | 15 | > TODO: paste kill ring cycle - paste transient state in spacemacs 16 | 17 | ## Discover projects 18 | 19 | ++spc++ ++"p"++ ++d++ to discover projects withing the directories specified in `projectile-project-search-path` 20 | 21 | ```emacs 22 | (setq projectile-project-search-path '(("~/projects" . 2) ("~/.config" . 1))) 23 | ``` 24 | 25 | ## Files 26 | 27 | ++spc++ ++"u"++ ++spc++ ++"f"++ ++"f"++ 28 | 29 | ++spc++ ++"f"++ ++"f"++ to open or create a new file. If a file is open in the current buffer, its path is used as the starting point. To create a file (and intermediate directories), type any additional path and file name. 30 | 31 | ++spc++ ++"p"++ ++"f"++ to list all files in the current project / workspace. Use this when you know the name of the project but not the path or to avoid navigating to the correct path. 32 | 33 | ??? WARNING "Project Cache Outdated" 34 | ++spc++ ++"p"++ ++"i"++ to udate the project cache moving directories and files, otherwise Doom will open a buffer for the old location 35 | 36 | ++spc++ ++"u"++ before a file command will also clear the cache and allow correct selection of files, e.g. 37 | 38 | ++spc++ ++"u"++ ++spc++ ++"f"++ ++"f"++ 39 | 40 | ### File diffs 41 | 42 | ++spc++ ++"f"++ ++"e"++ runs ediff to compare 2 files, prompting to select each file in turn. ++"j"++ ++"k"++ to navigate the differences between each file. ++"a"++ to copy change from first file to second. ++"b"++ to copy change from second file to first. 43 | 44 | ++spc++ ++"f"++ ++"3"++ runs ediff to compare 3 files. 45 | 46 | 47 | ## Windows 48 | 49 | ++spc++ ++"w"++ and one of ++"h"++ ++"j"++ ++"k"++ ++"l"++ for vim-style navigation of windows 50 | 51 | ++spc++ ++"w"++ ++"v"++ to create a new vertical window, ++spc++ ++"w"++ ++"h"++ for a new horizontal window 52 | 53 | # Sessions 54 | 55 | spc q s to save the current session, which should load when (re)starting Emacs 56 | 57 | ## Searching across a project 58 | 59 | ++spc++ ++slash++ to search across all files in a project, using ripgrep (if installed on OS execution path) 60 | 61 | ++ctrl+"c"+ctrl+"e"++ opens search results in a separate buffer for editing results. 62 | 63 | ++ctrl+"c"+ctrl+"c"++ or ++z++ ++z++ to commit changes 64 | 65 | 66 | !!! HINT "Narrow search results with Ripgrep switches" 67 | Use ripgrep switches before or after a search pattern, E.g. #-t clojure -- test or #test -- -t clojure. 68 | 69 | `rg --type-list` for comprehensive list of types supported by Ripgrep. Types can represent one or more file extensions. 70 | 71 | `#test -- -t clojure` only search for Clojure files (*.clj, *.cljc, *.cljs, *.cljx file extension ) 72 | 73 | `#test -- -g*.tar.gz` - search any file that matches a glob, i.e. file extension .tar.gz 74 | 75 | `#test#!cd` - search for test and filter results containing `cd` using consult sub-search feature 76 | 77 | Everything before the second # is filtered by ripgrep. 78 | 79 | Everything after the second # is filtered by Vertico using Orderless 23, where ! (negatation), = (literal), ~ (fuzzy), % (case insensitive) prefixes are supported. 80 | 81 | ++"#"++ delimiter can be replaced with any arbitrary character. E.g. %test%!cd or *test*!cd, useful when the search pattern starts with a `#` character 82 | -------------------------------------------------------------------------------- /docs/basics/snippets.md: -------------------------------------------------------------------------------- 1 | # snippets 2 | 3 | Yasnippets is provided by the `snippets` module 4 | 5 | Add snippets to the `.config/doom/snippets` directory, under a directory named after the major mode in which the snippet should be available, e.g. clojure snippets should be saved in the `.config/doom/clojure-mode/` directory. 6 | 7 | ## Creating snippets 8 | 9 | ++ctrl+"c"++ ++ctrl+"n"++ to create a new snippet in the current major mode (although that can be changed when saving the snippet) 10 | 11 | Visually select text before creating the snippet to create a snippet from that text. 12 | 13 | Edit the snippet using tab stops and place holders 14 | 15 | ++ctrl+"c"++ ++ctrl+"c"++ to commit the snippet, prompting for comfirmation of the major mode and if the snippet file should be saved. 16 | 17 | !!! HINT "Creating custom yasnippets" 18 | A Practicalli [detailed guide to writing snippets with yasnippet](https://practical.li/blog/posts/writing-custom-snippets-for-yasnippets/) 19 | 20 | 21 | ## Clojure LSP snippets 22 | 23 | Enable the `lsp` and `clojure` adding lsp as an option 24 | 25 | ```emacs 26 | lsp 27 | (clojure +lsp) 28 | ``` 29 | 30 | Clojure LSP contains its own snippets. 31 | 32 | [practicalli/clojure-lsp-config](https://github.com/practicalli/clojure-lsp-config) containes a range of snippets designed by Practicalli and used regularly. Add this configuration to `.config/clojure-lsp` or copy specific snippets to your clojure LSP configuration in the `:additionaal-snippets` key. 33 | 34 | ### Adding custom snippets 35 | 36 | !!! HINT "Custom snippets for Clojure LSP" 37 | A Practicalli [detailed guide for writing custom snippets for Clojure LSP](https://practical.li/blog/posts/code-snippets-for-clojure-lsp/) 38 | 39 | Edit the `config.edn` file. 40 | 41 | The `:additional-snippets` key has a collection of hash-maps, with each hash-map representing a snippet. 42 | 43 | `$n` represents a tab-stop, where the `TAB` key will jump throughout the snippet. `n` is an integer number to define the order of the tab-stops, e.g. `$1`, `$2`, $3. 44 | 45 | `$0` is a special tab-stop that denotes the end of the tab-stops, ending the snippet interaction. 46 | 47 | `${n:placeholder text}` allows text to be placed at the tab-stop to give an indication as to the value to be completed. The placeholder text is automatically highlighted when tabbing into the tab-stop, so typing a new value replaces the placeholder text. 48 | 49 | Highlighting and replacing the text does not work for the `$0` tab-stop, so placeholder text should not be used with this specific tab-stop. 50 | -------------------------------------------------------------------------------- /docs/basics/speaking-evil.md: -------------------------------------------------------------------------------- 1 | # Speaking Evil 2 | 3 | Evil is easier to learn if you learn to speak commands as sentences. 4 | 5 | First learn some verbs: 6 | 7 | `c` (change), `d` (delete), `g` go, `v` visual (select), `y` yank (copy) 8 | 9 | Then use those verbs with some modifiers (motions) 10 | 11 | `'` mark, `{ }` beginning/end of paragraph, `a` around, `f` find (includes character), `i` inside, `s` surround, `t` till (just before a character) 12 | 13 | Then learn the text objects you can apply verbs and modifiers too 14 | 15 | `b` block/parentheses, `p` paragraph, `s` sentence `t` tag - html/xml, `w` word 16 | 17 | 18 | ## Examples of speaking Evil 19 | 20 | Practice speaking evil with these examples 21 | 22 | | Keybinding | Description | 23 | |-------------|-----------------------------------------------------------------------| 24 | | `c i s` | change inside current sentence (change the whole sentence) | 25 | | `c i "` | change inside double quotes | 26 | | `c f )` | change from cursor to next `)` character | 27 | | `c s ' "` | change by the surrounding single quotes with double quotes | 28 | | `c t X` | change till the character `X` (not including `X`) | 29 | | `c /foo` | change until the first search result of ‘foo’ | 30 | | `d d` | delete current line | 31 | | `d i w` | delete inside the current word (delete word) | 32 | | `v t SPC` | visual select till the next `Space` character | 33 | | `v s ]` | visually select and surround with `[]` without spaces | 34 | | `v s [` | as above with `[ ]` with spaces between parens and content | 35 | | `g v` | go to last visual selection (select last visual selection) | 36 | | `v a p` | visually select around current paragraph | 37 | | `SPC v s "` | visually select current work and surround with `""` | 38 | | `v i w s "` | visually select, insert around current word, and surround with quotes | 39 | | `y y` | yank (copy) current line | 40 | | `y w` | yank (copy) current word | 41 | | `y @ a` | yank (copy) to mark `a` (`m a` creates a mark called `a`) | 42 | 43 | 44 | !!! HINT "Evil Reference and Tips" 45 | [Evil quick reference guide](vim-quick-reference.md) 46 | [Evil tips for developers](vim-tips-for-developers.md) 47 | [Speaking Vim](https://stackoverflow.com/questions/1218390/what-is-your-most-productive-shortcut-with-vim/1220118#1220118){target=_blank} 48 | -------------------------------------------------------------------------------- /docs/basics/structural-editing.md: -------------------------------------------------------------------------------- 1 | # Structural Editing with Smartparens 2 | 3 | 4 | ??? INFO "Smartparens enabled by default" 5 | Smartparens package is enabled by default in Doom emacs 6 | ```emacs title=".config/doom/init.el 7 | :config 8 | (default +bindings +smartparens) 9 | ``` 10 | 11 | 12 | ## Key bindins 13 | 14 | > TODO: documentation copied from Spacemacs to be reviewed 15 | 16 | 17 | ### Navigation 18 | 19 | | Key binding | Description | 20 | |-------------+-------------------------------------------------------------------------| 21 | | | Forward + Backward pairs | 22 | |-------------+-------------------------------------------------------------------------| 23 | | ~SPC k j~ | go forward to next closing parenthesis | 24 | | ~SPC k k~ | go backward to previous opening parenthesis | 25 | | ~SPC k l~ | go forward to next symbol | 26 | | ~SPC k h~ | go backward to previous symbol | 27 | | ~SPC k L~ | go forward to next sexp | 28 | | ~SPC k H~ | go backward to previous sexp | 29 | | ~SPC k $~ | go forward to the end of current sexp | 30 | | ~SPC k 0~ | go backward to the beginning of current sexp | 31 | |-------------+-------------------------------------------------------------------------| 32 | | | Other | 33 | |-------------+-------------------------------------------------------------------------| 34 | | ~SPC k U~ | go "up": to parent sexp backward | 35 | | ~SPC k %~ | go to other paren of the same pair | 36 | | ~SPC k I~ | go back to beginning of current expression and switch to =insert= state | 37 | 38 | ### Manipulation: 39 | 40 | | Key binding | Description | 41 | |-------------+--------------------------------------------------------------| 42 | | ~SPC k s~ | slurp forward: ~a (bs) c~ -> ~a (bs c)~ | 43 | | ~SPC k S~ | slurp backward: ~a (bs) c~ -> ~(a bs) c~ | 44 | | ~SPC k b~ | barf forward: ~(a bs c)~ -> ~(a bs) c~ | 45 | | ~SPC k B~ | barf backward: ~(a bs c)~ -> ~a (bs c)~ | 46 | | ~SPC k a~ | absorb: ~(a (bs ..))~ -> ~((bs a ..))~ | 47 | | ~SPC k c~ | convolute: ~(as (bs ..))~ -> ~(bs (as ..))~ | 48 | | ~SPC k t~ | transpose: ~(as bs)~ -> ~(bs as)~ | 49 | | ~SPC k J~ | join: ~(as) (bs)~ -> ~(as bs)~ | 50 | |-------------+--------------------------------------------------------------| 51 | | | Hybrid (= better for non-Lisp languages) commands | 52 | |-------------+--------------------------------------------------------------| 53 | | ~SPC k ` s~ | hybrid slurp forward | 54 | | ~SPC k ` p~ | hybrid push: ~as bs~ -> ~bs as~ | 55 | | ~SPC k ` t~ | hybrid transpose: ~as bs~ -> ~bs as~ | 56 | |-------------+--------------------------------------------------------------| 57 | | Note 1: | ~xs~ is one or multiple sexp, ~x~ is a single sexp | 58 | | Note 2: | point is at when presented, or in the list otherwise | 59 | 60 | ### Insertion: 61 | 62 | | Key binding | Description | 63 | |-------------+--------------------------------| 64 | | ~SPC k (~ | insert sexp before current one | 65 | | ~SPC k )~ | insert sexp after current one | 66 | | ~SPC k w~ | wrap a symbol with parenthesis | 67 | 68 | ### Deletion: 69 | 70 | | Key binding | Description | 71 | |-------------+---------------------------------------------------------------------| 72 | | ~SPC k ds~ | delete symbol | 73 | | ~SPC k Ds~ | delete symbol backward | 74 | | ~SPC k dw~ | delete word | 75 | | ~SPC k Dw~ | delete word backward | 76 | | ~SPC k dx~ | delete sexp: ~(as a ..)~ -> ~(as ..)~ | 77 | | ~SPC k Dx~ | delete sexp backward: ~(as a ..)~ -> ~(as ..)~ | 78 | | ~SPC k e~ | splice, killing forward: ~(as (bs cs) ds)~ -> ~(as bs ds)~ | 79 | | ~SPC k E~ | splice, killing backward: ~(as (bs cs) ds)~ -> ~(as cs ds)~ | 80 | | ~SPC k r~ | raise: ~(as b ..)~ -> ~b~ | 81 | | ~SPC k W~ | unwrap sexp: ~(as)~ -> ~as~ | 82 | |-------------+---------------------------------------------------------------------| 83 | | | Hybrid (= better for non-Lisp languages) commands | 84 | |-------------+---------------------------------------------------------------------| 85 | | ~SPC k ` k~ | hybrid delete sexp | 86 | |-------------+---------------------------------------------------------------------| 87 | | Note 1: | ~xs~ is one or multiple sexp, ~x~ is a single sexp | 88 | | Note 2: | point is at ~~ when presented, or in the list otherwise | 89 | -------------------------------------------------------------------------------- /docs/basics/vim-quick-reference.md: -------------------------------------------------------------------------------- 1 | # Vim Quick Reference 2 | A reference of the most common keybindings available in Vim Normal mode. 3 | 4 | ++period++ repeats the last keybinding sequence used in Vim Normal mode or a change made within a complete Vim Insert session. 5 | 6 | ## Moving around 7 | 8 | In **normal** mode you can keep your fingers resting on the main row of your keyboard to move around. 9 | 10 | | Key | action | 11 | |---------|---------------------------------| 12 | | ++"h"++ | move cursor left one character | 13 | | ++"j"++ | move cursor down one line | 14 | | ++"k"++ | move cursor up one line | 15 | | ++"l"++ | move cursor right one character | 16 | 17 | ++ctrl++ ++"k"++ / ++"j"++ to move the cursor up or down in a menu. 18 | 19 | 20 | ### Navigating the current line 21 | 22 | | Key | Action | 23 | |-----|----------------------------------------------| 24 | | `f` | to next character (you specify) | 25 | | `t` | to just before the next character | 26 | | `;` | repeat `f` or `t` search | 27 | | `w` | start of next word | 28 | | `W` | start of next word, white space delimited | 29 | | `e` | end of current word | 30 | | `b` | start of previous word | 31 | | `W` | end of next word, white space delimited | 32 | | `*` | to next matching symbol name | 33 | | `$` | end of current line | 34 | | `0` | start of current line | 35 | | `^` | start of non-whitespace | 36 | | `%` | jump to matching parens or next closed paren | 37 | 38 | 39 | ### Navigating the current buffer 40 | 41 | | Key | action | 42 | |-----------|------------------------------------------------------------------| 43 | | `gg` | start of buffer | 44 | | `G` | end of buffer | 45 | | `H` | move cursor to head of buffer | 46 | | `M` | move cursor to middle of buffer | 47 | | `L` | move cursor to bottom line of buffer | 48 | | `C-u` | jump up half a page | 49 | | `C-d` | jump down half a page | 50 | | `}` | move cursor forward by paragraph or block | 51 | | `{` | move cursor backward by paragraph or block | 52 | | `ma` | mark a line in a file with marker "a" | 53 | | ``a` | after moving around, go back to the exact position of marker "a" | 54 | | `'a` | after moving around, go back to line of marker "a" | 55 | | `:marks` | view all the marks | 56 | | `''` | go to the last place you were | 57 | | `[{` | jump back to the "{" at the beginning of the current code block | 58 | | `SPC j i` | jump using helm list of headings / functions | 59 | | `SPC j j` | avy-jump to character (specify) | 60 | | `SPC j l` | avy-jump to line | 61 | | `C-o` | jump back to previous cursor location (`evil-jump-backwards`) | 62 | | `C-i` | Go to newer position in jump list (opposite of `C-o`) | 63 | | `: 4` | go to line 4 | 64 | 65 | 66 | 67 | ## Searching 68 | 69 | ++slash++ for a basic search for the current buffer 70 | 71 | ++spc++ ++"s"++ ++"b"++ for a buffer search with popup results that can be navigated with ++ctrl++ ++"j"++ / ++"k"++ 72 | 73 | ++spc++ ++slash++ to search across the current project. Matches are listed in a popup buffer. 74 | 75 | * ++ctrl+"c"++ ++ctrl+"e"++ opens the search results in an editable buffer. 76 | * ++ctrl+"c"++ ++ctrl+"c"++ to commit changes 77 | * ++ctrl+"c"++ ++ctrl+"k"++ to cancel changes. 78 | 79 | !!! HINT "Boundary for search pattern" 80 | `\b` defines a boundary around the search term, limiting the matches to full word. For example `search\b` will match search, but not searching. 81 | 82 | 83 | | Key | Action | 84 | |-----|-----------------------------------------------| 85 | | `*` | search forward for the word under the cursor | 86 | | `#` | search backward for the word under the cursor | 87 | | `/` | search forward in current buffer | 88 | | `?` | search backward in current buffer | 89 | | `n` | once searching: find forward | 90 | | `N` | once searching: find backwards | 91 | 92 | 93 | 94 | ## Text Editing 95 | 96 | The following commands put you into the Evil Insert state 97 | 98 | | Key | Action | 99 | |-----|--------------------------------------| 100 | | `i` | insert state at cursor | 101 | | `I` | insert state at start of line | 102 | | `a` | append - insert state after cursor | 103 | | `A` | append - insert state at end of line | 104 | | `o` | new line after cursor | 105 | | `O` | new line before cursor | 106 | 107 | 108 | ## Return to Normal state 109 | 110 | **normal** should be the state used most of the time, except when adding new text in **insert** state. As soon as typing new text is done, form a habit of switching back to **normal** state. 111 | 112 | ++escape++ or press ++"f"++ ++"d"++ keys in extremely quick succession, to switching from **insert** to **normal** state. 113 | 114 | 115 | ??? Hint "fd - Evil Escape shortcut" 116 | practicalli/doom-emacs-config sets evil escape key binding to `fd` 117 | 118 | ```emacs title=".config/doom/+bindings.el 119 | (after! evil-escape 120 | (setq evil-escape-key-sequence "fd")) 121 | ``` 122 | ++"f"++ ++"d"++ in rapid succession is low risk alternative to pressing ++escape++ as if not typed correctly then either the next `d` character is searched for on the current line (as `f` moves to the next character), or nothing happens. 123 | 124 | ++"u"++ to undo any unwanted results 125 | 126 | 127 | ## Copy, cut, paste, undo, redo 128 | 129 | `v` in Vim normal mode changes to Visual select mode. Use the navigation keys or any other movement keys to select text to copy or cut. 130 | 131 | | Key | Action | 132 | |-------------------------|----------------------------------------------------| 133 | | ++"y"++ | copy (yank) selection and add to kill ring | 134 | | ++"x"++ | delete character at point and add to kill ring | 135 | | ++"X"++ | delete character before point and add to kill ring | 136 | | ++"p"++ | paste last entry from kill ring | 137 | | ++"p"++ ++meta+"y"++ | paste with kill-ring history menu | 138 | | ++"u"++ | undo | 139 | | ++ctrl+"r"++ | redo | 140 | | ++spc++ ++"i"++ ++"y"++ | insert value from kill ring history | 141 | 142 | !!! Hint "Undo tips" 143 | Undo reverts the last action in normal mode or all the changes made in **insert** state 144 | 145 | 146 | ## Replace and changing text 147 | 148 | | Key | Action | 149 | |-----------|----------------------------------------------| 150 | | `r` | replace the character under cursor | 151 | | `R` | replace multiple characters until `ESC` | 152 | | `cw` | change word from cursor to end | 153 | | `4 c w` | change 4 words | 154 | | `v e` | select from cursor to end of word | 155 | | `v i w` | select current word anywhere within the word | 156 | | `v i w c` | change current word/region | 157 | | `v i w d` | delete current word/region | 158 | | `d e` | delete from cursor to end of word | 159 | | `d w` | delete from cursor to start of next word | 160 | | `C` | change from cursor to end of line | 161 | | `D` | delete from cursor to end of line | 162 | | `d $` | delete from cursor to end of line | 163 | 164 | 165 | 166 | ## Delete commands 167 | 168 | | Key | Action | 169 | |---------|-------------------------------------------------| 170 | | `de` | delete to end of word, not including space | 171 | | `dw` | delete to end of word, including space | 172 | | `d$` | delete to end of line | 173 | | `dd` | delete the current line | 174 | | `4 d w` | delete 4 words | 175 | | `4 d $` | delete 4 lines to end | 176 | | `dt` | delete to a character (not including character) | 177 | | `dab` | delete a whole block / expression | 178 | | `dib` | delete contents of a block / expression | 179 | | `cab` | change all the block / expression | 180 | | `cib` | change inner block contents / expression | 181 | | `yab` | yank all block / expression | 182 | | `yib` | yank inner block contents / expression | 183 | 184 | 185 | 186 | ## Repeat commands 187 | 188 | | Key | Action | 189 | |------------------|----------------------------------| 190 | | `.` | repeat last command again | 191 | | ` ` | repeat command a number of times | 192 | 193 | The `.` keybinding will repeat the last command in normal mode or the last text edit in insert mode. 194 | 195 | Type a number before a command and that command will run that number of times. 196 | 197 | >####Hint::Inserting a comment border 198 | > Use the number repeat to create a border of 42 `;` characters. 199 | > Type `42` to repeat the command 42 times 200 | > Press `i` for insert mode 201 | > Press `;` as the character to repeat insert 202 | > Press `ESC` or `fd` to leave insert mode and insert all 42 `;` characters 203 | 204 | 205 | ## Transposing / swap 206 | 207 | | Key | Description | 208 | |----------------------|-------------------------------------------------------------| 209 | | `x p` or `SPC x t c` | transpose the current character with the next character | 210 | | `SPC x t w` | transpose the current character with the previous character | 211 | | `SPC x t l` | transpose current line with previous line | 212 | | `SPC k tf` | transpose expression | 213 | 214 | 215 | 216 | ## Comments - works for all major modes 217 | 218 | `SPC ; ;` or `g c c` to comment out the current line 219 | 220 | `SPC ;` or `g c` to comment out the currently selected region 221 | 222 | `M-;` creates a `;;` comment on an empty line, or `;` at the end of the text of the current line. 223 | 224 | To comment multiple lines you can use the repeat command style, especially useful if you are using relative line numbers. 225 | 226 | `g c 3 j` will comment the current line and the following two lines below. Comment in reverse using `g c 3 k`. 227 | 228 | In Visual state, `v`, select the lines you wish to comment and use `g c` to comment all the marked lines. Partially marked lines are not commented. 229 | 230 | 231 | http://spacemacs.org/layers/+vim/evil-commentary/README.html 232 | 233 | 234 | ## Working with Buffers 235 | 236 | To work with files in Emacs, they are first loaded into a **Buffer**. 237 | 238 | So when you open a file with `M-x find file` or `SPC f f` a new buffer is created so you can manage that file. 239 | 240 | Buffers are displayed in a window and you can change the window to show any of the current buffers. 241 | 242 | Here are the most commonly used buffer commands 243 | 244 | | Key | Command | Description | 245 | |-----------|--------------------------------|-------------------------------------------| 246 | | `SPC b b` | helm-mini | List current buffers | 247 | | `SPC b d` | kill-this-buffer | Kill current buffer | 248 | | `SPC b h` | home | Switch to Spacemacs home page | 249 | | `SPC b n` | next-buffer | Switch to next buffer | 250 | | `SPC b p` | previous-buffer | Switch to previous buffer | 251 | | `SPC b s` | switch-to-scratch-buffer | Switch to the **scratch** buffer | 252 | | `SPC b Y` | copy-whole-buffer-to-clipboard | Copy current buffer contents to kill ring | 253 | 254 | See the full buffer menu via `SPC b` 255 | 256 | ![Spacemacs Buffer Menu](/images/spacemacs-buffer-menu.png) 257 | 258 | 259 | ## Managing Files 260 | 261 | | Key | Description | 262 | |-------------|------------------------------------------------------| 263 | | `SPC f c` | copy file - save current buffer with a new file name | 264 | | `SPC f R` | change file name of current buffer | 265 | | `SPC f y n` | yank file name of current buffer | 266 | 267 | Also consider using treemacs and projectile 268 | 269 | 270 | ## Quit or Restart Emacs 271 | 272 | I recommend using the Spacemacs menu from **normal** mode to quit / restart Spacemacs. 273 | 274 | | Key | Action | 275 | |-----------|------------------------------------------------------------| 276 | | `SPC q q` | Quit Spacemacs | 277 | | `SPS q r` | Restart Spacemacs keeping current window and buffer layout | 278 | | `SPS q R` | Restart Spacemacs | 279 | 280 | 281 | > #### Hint::Work in progress - sorry 282 | > The rest of this section is work in progress and a little messy. 283 | 284 | 285 | ## Classic Vim commands 286 | 287 | > ####Todo::Reference section 288 | > The classic vim commands are also available, however, I dont think they are as nice to learn. Adding as reference for those used to Vim already and would miss them. 289 | 290 | ### Substitution 291 | 292 | | key | Action | 293 | |-------------------|----------------------------------------------| 294 | | `:s/old/new` | substitute new for the first old pattern | 295 | | `:s/old/new/g` | substitute new for all 'old's on a line | 296 | | `:#,#s/old/new/g` | substitute phrases between two line #'s type | 297 | | `:%s/old/new/g` | substitute all occurrences in the file | 298 | | `:%s/old/new/gc` | as above, asking for confirmation each time | 299 | 300 | 301 | ### External commands 302 | 303 | You can run external commands using `:!` followed by a command. For example: 304 | 305 | `:!ls` - run the `ls` command 306 | 307 | > Spacemacs shell can be configured to pop-up a shell buffer to run commands from the directory of the current buffer. 308 | 309 | 310 | ### Spelling Checking 311 | 312 | As you are typing in any(?) buffer then Spacemacs is checking your spelling as you type. If you type a word that Spacemacs does not recognise then that word is underscored in red. To correct a spelling: 313 | 314 | * Move to the word that is incorrectly spelt 315 | * `SPC S c` to change the word and show a list of suggested words 316 | * Either type in a new spelling or use `C-j` and `C-k` keys to move down and back up the list of words, using `RET` to select that word. 317 | 318 | 319 | ### Scrolling 320 | 321 | In evil command mode you can scroll just the text using the classic vi bindings. This does not scroll the cursor unless the cursor hist the top or bottom of the window, in which case the cursor stays at that window boundary. 322 | 323 | * `C-y` - scroll down 324 | * `C-e` - scroll text up 325 | 326 | 327 | ### Jump around 328 | 329 | `SPC j i` shows imenu that lists all the def and defn expressions in the current buffer, allowing you to jump to one of these definitions directly by typing its name or using `C-j` and `C-k` to select the name and pressing `RET` to jump to the name in the buffer 330 | 331 | 332 | `SPC j l` labels each line of the buffer with a short, unique character code. By entering the character code you are taken directly to the specific line. This is the `avy goto line` function and this works on all visible buffers by default, although it can be just shown on the current buffer (TODO: how is this set). 333 | 334 | ### Searching 335 | 336 | Search with `SPC /` 337 | -------------------------------------------------------------------------------- /docs/basics/workspaces.md: -------------------------------------------------------------------------------- 1 | # Using Workspaces 2 | 3 | Multiple workspaces are a convienient way to manage working with different projects. 4 | 5 | ++spc++ ++"l"++ is the workspace menu from practicalli/doom-emacs-config (++spc++ ++tab++ in Doom Emacs) 6 | 7 | ++spc++ ++"p"++ ++"p"++ and selecting a project will open the project within a workspace 8 | 9 | ++spc++ ++"l"++ ++"l"++ lists existing workflows 10 | 11 | ++spc++ ++"l"++ ++tab++ jumps to the last open workspace (use to toggle between two projects) 12 | 13 | ++spc++ ++"l"++ ++"d"++ displays existing workflows as tabs at the bottom of the frame 14 | 15 | 16 | ## Isolated buffer-list 17 | 18 | ++spc++ ++"b"++ ++"b"++ is workspace-restricted, showing open buffers only from the scope of the current workspace (projeect). 19 | 20 | ++spc++ ++"b"++ ++b++ shows the global list of buffers, along with any typically hidden buffers, e.g. `*messages*` 21 | 22 | 23 | ## Automatic workspaces 24 | 25 | A workspace is automatically created (and switched to) when you: 26 | 27 | - Create a new frame with `make-frame` 28 | - Switch to a project using `projectile-switch-project` 29 | 30 | 31 | ## Session persistence 32 | 33 | ++spc++ ++"q"++ ++"s"++ to save the current session, including open workspaces and buffers, to , `~/.config/emacs/.local/etc/workspaces/autosave`. ++spc++ ++"q"++ ++"s"++ to choose a different file to save the session. 34 | 35 | ++spc++ ++"q"++ ++"L"++ (~+workspace/load-session~) to load a previous session 36 | 37 | You can supply either a name to load a specific session to replace your current one. 38 | 39 | ### Workspace persistence 40 | 41 | ++spc++ ++"l"++ ++"s"++ (~+workspace/save~) to save the current workspace to a file. If workspaces are already saved to file, a prompt appears to confirm keeping the other saved workspaces. 42 | 43 | ++spc++ ++"l"++ ++"l"++ (~+workspace/load~) to load workspaces from the persisted workspace file, `~/.config/emacs/.local/etc/workspaces/autosave` 44 | 45 | ++spc++ ++"l"++ ++"L"++ to load a workspace that was previously created in the current session but was not loaded automatically 46 | 47 | ## Commands 48 | 49 | Default keybindings (defined in `/config/default/+evil-bindings.el` 50 | 51 | | command | description | 52 | |-----------------------------------|------------------------------------------------------------| 53 | | ~+workspace/new~ | Create a new, blank workspace | 54 | | ~+workspace/display~ | Display open workspaces in the mode-line | 55 | | ~+workspace/load~ | Load a saved workspace into the current session | 56 | | ~+workspace/restore-last-session~ | Restore last session | 57 | | ~+workspace/rename~ | Rename the current workspace | 58 | | ~+workspace/save~ | Save the current workspace to a file | 59 | | ~+workspace/switch-to~ | Switch to an open workspace | 60 | | ~+workspace/other~ | Switch to last workspace | 61 | | ~+workspace/switch-left~ | Switch to previous workspace | 62 | | ~+workspace/switch-right~ | Switch to next workspace | 63 | | ~+workspace/delete~ | Delete the current workspace | 64 | | ~+workspace/kill-session~ | Clears the current session (kills all windows and buffers) | 65 | -------------------------------------------------------------------------------- /docs/clojure-workflow/index.md: -------------------------------------------------------------------------------- 1 | # Clojure Developmement Workflow 2 | 3 | ??? INFO "Aliases used in examples are defined in practicalli/clojure-deps-edn" 4 | [practicalli/clojure-deps-edn](https://github.com/practicalli/clojure-deps-edn) contains a wide range of aliases and community tools for Clojure CLI projects. 5 | 6 | `:env/dev` adds `dev` directory to the class path, used to load `dev/user.clj` file and run development tools on REPL startup 7 | 8 | `:env/test` adds `test` directory to include unit tests and common testing libraries 9 | 10 | `:repl/rebel` runs a rich terminal UI and an nREPL server to allow connection from [Clojure aware editors](https://practical.li/clojure/clojure-editors/) 11 | 12 | 13 | ## Start Clojure REPL 14 | 15 | === "Command Line" 16 | 17 | Start a REPL in a terminal window with a rich REPL UI prompt, with auto-completion, syntax highlighting, multi-line editing and documentation. 18 | ```shell 19 | clojure -M:env/dev:env/test:repl/rebel 20 | ``` 21 | 22 | Or start a headless REPL if only using the REPL via the editor 23 | ```shell 24 | clojure -M:env/dev:env/test:repl/headless 25 | ``` 26 | 27 | ++comma++ ++"c"++ to connect to an existing Clojure REPL and follow the prompts to connect to `localhost` 28 | 29 | 30 | === "Doom Emacs" 31 | Doom Emacs can launch a REPL process and connect to that process without leaving Emacs. External tools (Clojure CLI, Leiningen) are used to actually start the REPL process and CIDER manages the connection and communication with the REPL process from within Doom Emacs. 32 | 33 | ++comma++ ++single-quote++ to start a Clojure REPL using `cider-jack-in` 34 | 35 | Include a `.dir-locals.el` file in the root of the Clojure project to include Clojure CLI aliases 36 | ```elisp 37 | ((clojure-mode . ((cider-preferred-build-tool . clojure-cli) 38 | (cider-clojure-cli-aliases . ":env/dev:env/test")))) 39 | ``` 40 | 41 | 42 | ## Evaluate code 43 | 44 | ++comma++ ++"e"++ opens the evaluation menu 45 | 46 | 47 | ## Snippets 48 | 49 | Snippets from Yasnippets appear when typing matches the name of the snippet defined in the major mode. 50 | 51 | Clojure also has snippets defined from Clojure LSP. 52 | 53 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Practicalli Doom Emacs 2 | 3 | Practicalli Doom Emacs is a guide to Clojure REPL Driven Development with Doom Emacs configuration and Practicalli customization. 4 | 5 | Doom is not aimed at Emacs beginners (unless the aim is to learn Emacs in more depth). There is limited official documentation, although there is a healthy community support. 6 | 7 | ??? INFO "Looking for a batteries included approach?" 8 | [Practicalli Spacemacs](https://practical.li/spacemacs) and [practicalli/spacemacs.d](https://github.com/practicalli/spacemacs.d) provide all the Emacs features needed for Clojure, with just two Git clone commands. Spacemacs is a community configuration for Emacs with a very large community and very detailed documentation. 9 | 10 | ??? WARNING "Book development on hold" 11 | Practicalli Doom Emacs and its associated configuration project are currently on hold as Doom Emacs is not currently used by Practicalli. 12 | 13 | The book was started in December 2022 with little knowledge of Doom Emacs, so is mostly a journal of things that have been learned as Practicalli tries to create an effective development workflow, especially with Clojure. 14 | 15 | Should Practicalli use Doom Emacs regularly again then further content will be added as new things are discovered, to aid in the learning and effective use of Doom Emacs. 16 | 17 | 18 | ## Practicalli Doom Emacs configuration 19 | 20 | [practicalli/doom-emacs-config repository](https://github.com/practicalli/doom-emacs-config){target=_blank} contains a customised configuration for Clojure development and supporting tools. [Browse the repository online](https://github.com/practicalli/doom-emacs-config){target=_blank} or fork / clone the repository 21 | 22 | === "Free Desktop XDG Config" 23 | ```bash 24 | git clone https://github.com/practicalli/doom-emacs-config.git $XDG_CONFIG_HOME/doom` 25 | ``` 26 | The Practicalli configuration should replace the `~/.config/doom/` directory created by the `doom install` command. 27 | 28 | === "Classic Config" 29 | ```bash 30 | git clone https://github.com/practicalli/doom-emacs-config.git $HOME/.doom.d` 31 | ``` 32 | The Practicalli configuration should replace the `~/.doom.d/` directory created by the `doom install` command. 33 | 34 | 35 | ![Emacs Doom with Practicalli customisations](https://raw.githubusercontent.com/practicalli/graphic-design/live/doom-emacs/doom-emacs-practicalli-dark.png#only-dark) 36 | ![Emacs Doom with Practicalli customisations](https://raw.githubusercontent.com/practicalli/graphic-design/live/doom-emacs/doom-emacs-practicalli-light.png#only-light) 37 | 38 | 39 | ## REPL Driven Development 40 | 41 | [![Clojure repl driven development using Clojure aware editor](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/clojure-repl-driven-development-lifecycle-concept.png)](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/clojure-repl-driven-development-lifecycle-concept.png) 42 | 43 | The REPL is the [Clojure interactive environment](introduction/repl-workflow.md) used to create an run all code. You will quickly get a feel for Clojure by evaluating, breaking, fixing and extending code in the REPL, all the while getting instant feedback on what your code is doing. 44 | 45 | As we work through code we will discuss the concepts behind Clojure, including functional programming, "pure" functions and a stateless approach with persistent data structures, changing state safely, Java interoperability and tooling around Clojure. 46 | 47 | 48 | ## Resources 49 | 50 | * [Practicalli Clojure](https://practical.li/clojure) for a practical introduction learning Clojure and provides [practicalli/clojure-deps-edn configuration](https://github.com/practialli/clojure-deps-edn) to add community tools and common aliases to Clojure CLI. 51 | * [Practicalli YouTube channel](https://youtube.com/practicalli) - 100+ hours of Clojure related videos 52 | * [Practicalli website](https://practical.li/) blog, books and videos to support your journey into Clojure 53 | 54 | 55 | ## Discussions and feedback 56 | 57 | [Contributions are welcome via GitHub issues and pull requests](introduction/contributing.md), or discuss the book on the Clojurians Slack community. 58 | 59 | [practicalli channel - Clojurians Slack Community](https://clojurians.slack.com/messages/practicalli){target=_blank .md-button} 60 | 61 | [Free Clojurians slack community account](https://clojurians.net/){target=_blank .md-button} 62 | 63 | 64 | ## Navigate the book 65 | 66 | Use the mouse or built-in key bindings to navigate the pages of the book 67 | 68 | - ++p++ , ++comma++ : go to previous page 69 | - ++n++ , ++period++ : go to next page 70 | 71 | Use the search box to quickly find a specific topic 72 | 73 | - ++f++ , ++s++ , ++slash++ : open search dialog 74 | - ++arrow-down++ , ++arrow-up++ : select next / previous result 75 | - ++esc++ , ++tab++ : close search dialog 76 | - ++enter++ : follow selected result 77 | 78 | 79 | ## Sponsor Practicalli 80 | 81 | [![Sponsor practicalli-johnny](https://raw.githubusercontent.com/practicalli/graphic-design/live/buttons/practicalli-github-sponsors-button.png){ align=left loading=lazy }](https://github.com/sponsors/practicalli-johnny/) 82 | 83 | All sponsorship funds are used to support the continued development of [Practicalli series of books and videos](https://practical.li/){target=_blank}, although most work is done at personal cost and time. 84 | 85 | Thanks to [Cognitect](https://www.cognitect.com/){target=_blank}, [Nubank](https://nubank.com.br/){target=_blank} and a wide range of other [sponsors](https://github.com/sponsors/practicalli-johnny#sponsors){target=_blank} from the Clojure community for your continued support 86 | 87 | 88 | ## Creative commons license 89 | 90 |
91 | Creative Commons License 92 | This work is licensed under a Creative Commons Attribution 4.0 ShareAlike License (including images & stylesheets). 93 |
94 | -------------------------------------------------------------------------------- /docs/install/bindings.md: -------------------------------------------------------------------------------- 1 | # Key Bindings 2 | 3 | [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank} replaces many of the default Doom key bindings as well as adding more key bindings 4 | 5 | `map!` Doom macro is used to define new key bindings. Existing Doom key bindings are replaced by first setting the binding to `nil` then adding a new definition. 6 | 7 | Most Practicalli key bindings are defined in the `~/.config/doom/+bindings.el` configuration file, or in a major mode specific file e.g. `~/.config/doom/+clojure.el` 8 | 9 | ??? INFO "Doom - basic guide to rebinding keys" 10 | [How to rebind keys](https://discourse.doomemacs.org/t/how-to-re-bind-keys/) - Doom Emacs discord 11 | 12 | 13 | ## Leader / Local leader 14 | 15 | ++spc++ is the leader key that opens the which-key menu, driving many of the menu based commands. 16 | 17 | ++comma++ replaces the Doom local leader, `SPC m` which is considered a major mode menu entry under the leader key so not really a shortcut to access the major mode context specific menu. 18 | 19 | ```emacs title=".config/doom/+bindings.el" 20 | (setq doom-localleader-key ",") 21 | ``` 22 | 23 | 24 | ## M-x Emacs command list 25 | 26 | ++spc++ ++colon++ is the Doom default to list Emacs commands (`M-x`), aligning with the `:` character used to issue vim commands 27 | 28 | ++spc++ ++spc++ is `M-x` in Spacemacs, so [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank} replaces the existing key binding that Doom defines to open a file (provided by `SPC f f`) 29 | 30 | 31 | ```emacs title=".config/doom/+bindings.el" 32 | (map! :leader 33 | "SPC" nil 34 | :desc "M-x" "SPC" #'execute-extended-command) 35 | ``` 36 | 37 | > `SPC :` key binding is kept to allow for migration to the Doom key binding. 38 | 39 | 40 | ## Evil escape 41 | 42 | `fd` is used for Evil Escape to provide an alternative to the ++esc++ key that keeps fingers on the home row of the keyboard 43 | 44 | ```emacs title=".config/doom/+bindings.el" 45 | (after! evil-escape 46 | (setq evil-escape-key-sequence "fd")) 47 | ``` 48 | 49 | 50 | # Buffers 51 | 52 | ++spc++ ++tab++ switches to last open buffer, providing a convenient way to toggle between two buffers. 53 | 54 | ++spc++ ++"b"++ ++tab++ added to help discovery of this toggle approach 55 | 56 | ```emacs title=".config/doom/+bindings.el" 57 | (map! :leader 58 | "TAB" nil 59 | :desc "Last Buffer" "TAB" #'evil-switch-to-windows-last-buffer) 60 | 61 | (map! :leader 62 | (:prefix "b" 63 | :desc "Dashboard" "h" #'+doom-dashboard/open 64 | :desc "Toggle Last" "TAB" #'evil-switch-to-windows-last-buffer)) 65 | ``` 66 | 67 | > Replaces Doom `SPC TAB` used for the workspaces menu, which is also replaced by `SPC l` 68 | 69 | 70 | ## Workspaces 71 | 72 | ++spc++ ++"l"++ replaces Doom `SPC TAB` to open the workspaces menu to align with Spacemacs (layout) approach. This frees `SPC TAB` to jump to the last open buffer, as in Spacemacs. 73 | 74 | 75 | ```emacs title=".config/doom/+bindings.el" 76 | (map! :leader 77 | (:prefix-map ("TAB" . nil)) 78 | (:prefix ("l". "Layouts") 79 | :desc "Last Layout" "" #'+workspace/other 80 | :desc "Display Tabs" "d" #'+workspace/display 81 | :desc "Delete layout" "D" #'+workspace/delete 82 | :desc "Layout list" "l" #'+workspace/switch-to 83 | :desc "Load Layout" "L" #'+workspace/load 84 | :desc "New Layout" "n" #'+workspace/new 85 | :desc "Rename Layout" "r" #'+workspace/rename 86 | :desc "Restore session" "R" #'+workspace/restore-last-session 87 | :desc "Save Layout" "s" #'+workspace/save 88 | :desc "Kill Session" "x" #'+workspace/kill-session 89 | :desc "Switch to 0" "0" #'+workspace/switch-to-0 90 | :desc "Switch to 1" "1" #'+workspace/switch-to-1 91 | :desc "Switch to 2" "2" #'+workspace/switch-to-2 92 | :desc "Switch to 3" "3" #'+workspace/switch-to-3 93 | :desc "Switch to 4" "4" #'+workspace/switch-to-4 94 | :desc "Switch to 5" "5" #'+workspace/switch-to-5 95 | :desc "Switch to 6" "6" #'+workspace/switch-to-6 96 | :desc "Switch to 7" "7" #'+workspace/switch-to-7 97 | :desc "Switch to 8" "8" #'+workspace/switch-to-8 98 | :desc "Switch to 9" "9" #'+workspace/switch-to-9)) 99 | ``` 100 | 101 | 102 | 103 | ## Treemacs 104 | 105 | ++spc++ ++"p"++ ++"t"++ toggles treemacs project browser from project menu 106 | 107 | ```emacs title=".config/doom/+bindings.el" 108 | (map! :leader 109 | (:prefix "p" 110 | "t" nil ; disable project todos key binding 111 | :desc "Project browser" "t" #'+treemacs/toggle)) 112 | ``` 113 | 114 | 115 | ## Version Control 116 | 117 | ++spc++ ++"g"++ ++"s"++ to call Magit Status, rather than the Doom binding to stage hunk at point 118 | 119 | Practicalli always uses Magit status menu to manage changes, so adopting the Spacemacs binding. 120 | 121 | ```emacs title=".config/doom/+bindings.el" 122 | (map! :leader 123 | (:prefix "g" 124 | :desc "" "s" nil ; remove existing binding 125 | :desc "Magit Status" "s" #'magit-status)) 126 | ``` 127 | -------------------------------------------------------------------------------- /docs/install/clojure-configuration.md: -------------------------------------------------------------------------------- 1 | # Clojure configuration 2 | 3 | Enable the Clojure module with LSP support in the `~/.config/doom/init.el` configuration file 4 | 5 | ```emacs 6 | (clojure +lsp) 7 | lsp 8 | ``` 9 | 10 | Use the doom command to load the modules 11 | 12 | ```shell 13 | doom sync 14 | ``` 15 | 16 | ## Cider configuration 17 | 18 | Define variables to configure CIDER 19 | 20 | ```emacs title="~/.config/doom/config.el" 21 | (use-package! cider 22 | :after clojure-mode 23 | :config 24 | (setq cider-show-error-buffer t ;'only-in-repl 25 | cider-font-lock-dynamically nil ; use lsp semantic tokens 26 | cider-eldoc-display-for-symbol-at-point nil ; use lsp 27 | cider-prompt-for-symbol nil 28 | cider-use-xref nil ; use lsp 29 | 30 | cider-repl-pop-to-buffer-on-connect nil ; REPL buffer shown at starup 31 | clojure-enable-kaocha-runner t ; enable Kaocha test runner 32 | cider-repl-display-help-banner nil ; disable help banner 33 | cider-print-fn 'puget ; pretty printing with sorted keys / set values 34 | cider-result-overlay-position 'at-point ; results shown right after expression 35 | cider-overlays-use-font-lock t 36 | cider-repl-buffer-size-limit 100 ; limit lines shown in REPL buffer 37 | cider-repl-history-size 42 38 | ) 39 | (set-lookup-handlers! '(cider-mode cider-repl-mode) nil) ; use lsp 40 | (set-popup-rule! "*cider-test-report*" :side 'right :width 0.4) 41 | (set-popup-rule! "^\\*cider-repl" :side 'bottom :quit nil) 42 | ;; use lsp completion 43 | (add-hook 'cider-mode-hook (lambda () (remove-hook 'completion-at-point-functions #'cider-complete-at-point)))) 44 | 45 | (use-package! clojure-mode 46 | :config 47 | (setq clojure-indent-style 'align-arguments 48 | clojure-align-forms-automatically t 49 | clojure-toplevel-inside-comment-form t ;; evaluate expressions in comment as top level 50 | )) 51 | ``` 52 | 53 | !!! Hint "Restart Doom Emacs after larger changes" 54 | ++spc++ ++"q"++ ++"r"++ to restart Doom Emacs when significant changes are made or something is not working correctly 55 | 56 | 57 | ## Clojure CLI 58 | 59 | [Practicalli Clojure install guide](https://practical.li/clojure/clojure-cli/install/){target=_blank .md-button} 60 | 61 | [Clojure CLI](https://clojure.org/guides/deps_and_cli){target=_blank} provides a way to run Clojure code, packaged Clojure (jar) and of course run a Clojure REPL. 62 | 63 | [Practicalli Clojure install guide](https://practical.li/clojure/clojure-cli/install/){target=_blank} details prerequisites, Clojure install options and supporting tools for an enhanced developer workflow. Or visit the [Clojure Getting Started guide](https://clojure.org/guides/getting_started){target=_blank} for just the Clojure CLI. 64 | 65 | [practicalli/clojure-deps-edn provides a wide range of community tools](https://practical.li/clojure/clojure-cli/install/community-tools.html){target=_blank} that can easily be added to the development environment and used across all projects. 66 | 67 | !!! WARNING "Aliases are required for many command examples" 68 | Without [installing practicalli/clojure-deps-edn](https://practical.li/clojure/clojure-cli/install/community-tools.html){target=_blank} many commands provided in this book will not work, unless the same alias configuration is added to a either a project or user level `deps.edn` configuration. 69 | 70 | 71 | ## Clojure LSP 72 | 73 | [Clojure LSP installation guide](https://clojure-lsp.io/){target=_blank .md-button } 74 | [Practicalli Clojure LSP configuration](http://github.com/practicalli/clojure-lsp-config){target=_blank .md-button} 75 | 76 | ![Clojure Language Server Protocol LSP](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/clojure-language-server.png) 77 | 78 | Clojure LSP provides a [standard set of features](https://emacs-lsp.github.io/lsp-mode/){target=_blank} for editing and manipulating source code, e.g. autocompletion, code navigation, refactor code, inline syntax errors and idiom warnings. 79 | 80 | !!! INFO "LSP and the REPL" 81 | The REPL is used to design Clojure effectively by providing instant feedback on code expressions as they are written and evaluated. A REPL based workflow supports the most effective approach to development of Clojure apps and services. 82 | Clojure LSP supports the editing activities to write Clojure code effectively, providing a static analysis of the code base that drives advance editing, navigation and refactor tasks. 83 | 84 | [Install the Clojure LSP command line tool](https://clojure-lsp.io/){target=_blank} and configure `~./config/clojure-lsp/config.edn` or use [Practicalli Clojure LSP configuration](http://github.com/practicalli/clojure-lsp-config){target=_blank} which provides a complete configuration for clojure-lsp (`config.edn`), including a wide range of snippets and less restrictive formatting rules (`cljfmt.edn`). 85 | 86 | 87 | === "Free Desktop XDG Config" 88 | 89 | Clone via SSH 90 | ```shell 91 | git clone -o practicalli git@github.com:practicalli/clojure-lsp-config.git $XDG_CONFIG_HOME/clojure-lsp 92 | ``` 93 | 94 | Clone via HTTPS 95 | ```shell 96 | git clone -o practicalli https://github.com/practicalli/clojure-lsp-config.git $XDG_CONFIG_HOME/clojure-lsp 97 | ``` 98 | 99 | === "Classic Config" 100 | Clone via SSH 101 | ```shell 102 | git clone -o practicalli git@github.com:practicalli/clojure-lsp-config.git $HOME/.clojure-lsp 103 | ``` 104 | 105 | Clone via HTTPS 106 | ```shell 107 | git clone -o practicalli https://github.com/practicalli/clojure-lsp-config.git $HOME/.clojure-lsp 108 | ``` 109 | 110 | Run the clojure-lsp command in a terminal to ensure the install was successful. 111 | 112 | ```shell 113 | clojure-lsp -v 114 | ``` 115 | 116 | ??? INFO "Clojure LSP and clj-kondo" 117 | Clojure LSP includes clj-kondo to provide [an implementation of the Language Server Protocol for the Clojure Language](https://clojure-lsp.io/){target=_blank}. clj-kondo provides static analysis of source code files, providing subtle warnings as Clojure code is written to help the developer follow idioms and avoid syntatic errors. 118 | 119 | 120 | 121 | ## References 122 | 123 | - [Configure Emacs as a Clojure IDE guide](https://emacs-lsp.github.io/lsp-mode/tutorials/clojure-guide/) 124 | - [A guide on disabling/enabling lsp-mode features](https://emacs-lsp.github.io/lsp-mode/tutorials/how-to-turn-off/) 125 | - [Emacs LSP UI website](https://emacs-lsp.github.io/lsp-ui/) and [emacs-lsp/lsp-ui repository](https://github.com/emacs-lsp/lsp-ui) 126 | -------------------------------------------------------------------------------- /docs/install/completion.md: -------------------------------------------------------------------------------- 1 | # Completion with Vertico 2 | 3 | Vertico module enhances the Emacs search and completion experience, with united interface for project search and replace, powered by [ripgrep](https://github.com/BurntSushi/ripgrep/) 4 | 5 | The primary packages are: 6 | 7 | - Vertico - vertical completion user interface 8 | - Consult - suite of useful commands using ~completing-read~ 9 | - Embark - set of minibuffer actions 10 | - Marginalia - annotations to completion candidates 11 | - Orderless - additional filtering methods 12 | 13 | Consult can use several external tools which must be installed to use their features 14 | 15 | - [fzf](https://github.com/junegunn/fzf) 16 | - [Dash docsets](https://kapeli.com/dash) 17 | - [pass](https://www.passwordstore.org/) 18 | 19 | 20 | ## Module flags 21 | - +childframe 22 | Display completion candidates in a [child frame](https://www.gnu.org/software/emacs/manual/html_node/elisp/Child-Frames.html) rather than an overlay or tooltip. *Requires GUI Emacs.* 23 | 24 | - +icons :: 25 | Add icons to =file= and =buffer= category completion selections. 26 | 27 | 28 | ## Vertico keybindings 29 | 30 | When in an active Vertico completion session, the following doom added keybindings are available: 31 | 32 | | Keybind | Description | 33 | |----------------------------------------|----------------------------------------------------------------| 34 | | ++ctrl+"k"++ | (evil) Go to previous candidate | 35 | | ++ctrl+"j"++ | (evil) Go to next candidate | 36 | | ++ctrl+meta+"k"++ | (evil) Go to previous group | 37 | | ++ctrl+meta+"j"++ | (evil) Go to next group | 38 | | ++ctrl+semi-colon++ or ++spc++ ++"a"++ | Open an ~embark-act~ menu to chose a useful action | 39 | | ++ctrl+"c"++ ++ctrl+semi-colon++ | export the current candidate list to a buffer | 40 | | ++ctrl+"c"++ ++ctrl+"l"++ | ~embark-collect~ the current candidate list (collect verbatim) | 41 | | ++ctrl+spc++ | Preview the current candidate | 42 | 43 | `embark-act` will prompt you with a =which-key= menu with useful commands on the selected candidate or candidate list, depending on the completion category. 44 | 45 | !!! HINT "Marginalia annotaions on help menu" 46 | ++ctrl+"h"++ shows a help menu of options with a Vertico buffer showing more detailed descriptions from Marginalia annotations 47 | 48 | 49 | ## Jump-to navigation 50 | 51 | Navigate within a project using projectile 52 | 53 | https://assets.doomemacs.org/completion/vertico/projectile.png 54 | 55 | | Keybind | Description | 56 | |-------------------------|-------------------------------------| 57 | | ++spc++ ++"p"++ ++"f"++ | Jump to file in project | 58 | | ++spc++ ++"f"++ ++"f"++ | Jump to file from current directory | 59 | | ++spc++ ++"s"++ ++"i"++ | Jump to symbol in file | 60 | 61 | 62 | 63 | ## Project search & replace 64 | 65 | This module provides interactive text search and replace using ripgrep. 66 | 67 | | Keybind | Description | 68 | |-------------------------|--------------------------| 69 | | ++spc++ ++"s"++ ++"p"++ | Search project | 70 | | ++spc++ ++"s"++ ++"P"++ | Search another project | 71 | | ++spc++ ++"s"++ ++"d"++ | Search this directory | 72 | | ++spc++ ++"s"++ ++"D"++ | Search another directory | 73 | 74 | https://assets.doomemacs.org/completion/vertico/search.png 75 | 76 | ++spc++ ++"u"++ universal argument prefix to commands instructs the search tool to include ignored file patterns. 77 | 78 | ++ctrl+c+ctrl+"e"++ to send the search results to an editable buffer 79 | 80 | 81 | ++"Z"++ ++"Z"++ or ++ctrl+c+ctrl+"c"++ to commit changes 82 | 83 | ++"Z"++ ++"Q"++ or ++ctrl+c+ctrl+"k"++ to abort changes 84 | 85 | https://assets.doomemacs.org/completion/vertico/search-replace.png 86 | 87 | 88 | ## In-buffer searching 89 | 90 | This module provides some in buffer searching bindings: 91 | 92 | - [[kbd:][spc s s]] (~isearch~) 93 | - [[kbd:][spc s S]] (~+vertico/search-symbol-at-point~ via ~consult-line~) 94 | - [[kbd:][spc s b]] (~consult-line~) 95 | 96 | https://assets.doomemacs.org/completion/vertico/buffer-search.png 97 | 98 | An ~occur-edit~ buffer can be opened from ~consult-line~ with [[kbd:][C-c C-e]]. 99 | 100 | ## Vertico integration 101 | 102 | | Keybind | Description | 103 | | ------------ | ----------------------------- | 104 | | ++"M"++ ++"x"++ or ++spc++ ++colon++ | Enhanced M-x | 105 | | ++spc++ ++quote++ | Resume last Vertico session | 106 | 107 | 108 | ### Jump to files, buffers or projects 109 | 110 | | Keybind | Description | 111 | | ------------------ | --------------------------------------- | 112 | | ++spc++ ++enter++ | Find bookmark | 113 | | ++spc++ ++"f"++ ++"f"++ or ++spc++ ++period++ | Browse from current directory | 114 | | ++spc++ ++"p"++ ++"f"++ or ++spc++ ++spc++ | Find file in project | 115 | | ++spc++ ++"f"++ ++"f"++ | Find recently opened file | 116 | | ++spc++ ++"p"++ ++"f"++ | Open another project | 117 | | ++spc++ ++"b"++ ++"b"++ or ++spc++ ++comma++ | Switch to buffer in current workspace | 118 | | ++spc++ ++"b"++ ++"B"++ or ++spc++ ++less-than++ | Switch to buffer | 119 | 120 | [[kbd:][spc b b]] and [[kbd:][spc ,]] support changing the workspace you're selecting a buffer from 121 | via [[https://github.com/minad/consult#narrowing-and-grouping][Consult narrowing]], e.g. if you're on the first workspace, you can switch to 122 | selecting a buffer from the third workspace by typing [[kbd:][3 spc]] into the prompt, or 123 | the last workspace by typing [[kbd:][0 spc]]. 124 | 125 | [[kbd:][spc f f]] and [[kbd:][spc .]] support exporting to a [[kbd:][wdired]] buffer using [[kbd:][C-c C-e]]. 126 | 127 | ## Search 128 | | Keybind | Description | 129 | |---------+-------------------------------------------| 130 | | [[kbd:][spc p t]] | List all TODO/FIXMEs in project | 131 | | [[kbd:][spc s b]] | Search the current buffer | 132 | | [[kbd:][spc s d]] | Search this directory | 133 | | [[kbd:][spc s D]] | Search another directory | 134 | | [[kbd:][spc s i]] | Search for symbol in current buffer | 135 | | [[kbd:][spc s p]] | Search project | 136 | | [[kbd:][spc s P]] | Search another project | 137 | | [[kbd:][spc s s]] | Search the current buffer (incrementally) | 138 | 139 | ##* File Path Completion 140 | Note that Emacs allows you to switch directories with shadow paths, for example 141 | starting at =/foo/bar/baz=, typing =/foo/bar/baz/~/= will switch the searched 142 | path to the home directory. For more information see ~substitute-in-file-name~ 143 | and ~file-name-shadow-mode~. This module will erase the "shadowed" portion of 144 | the path from the minibuffer, so in the previous example the path will be reset 145 | to =~/=. 146 | 147 | ## Consult 148 | 149 | * Multiple candidate search 150 | This module modifies the default keybindings used in 151 | ~consult-completing-read-multiple~: 152 | | Keybind | Description | 153 | |---------+-------------------------------------------------------------| 154 | | [[kbd:][TAB]] | Select or deselect current candidate | 155 | | [[kbd:][RET]] | Enters selected candidates (also toggles current candidate) | 156 | 157 | ##* Async search commands 158 | :PROPERTIES: 159 | :ID: 4ab16bf0-f9e8-4798-8632-ee7b13d2291e 160 | :END: 161 | Consult async commands (e.g. ~consult-ripgrep~) will have a preceding separator 162 | character (usually ~#~) before the search input. This is known as the =perl= 163 | splitting style. Input typed after the separator will be fed to the async 164 | command until you type a second seperator, afterwhich the candidate list will be 165 | filtered with Emacs instead (and can be filtered using [[doom-package:orderless]], for example). 166 | The specific seperator character can be changed by editing it, and might be 167 | different if the initial input already contains =#=. 168 | 169 | Note that grep-like async commands translate the input (between the first and 170 | second =#=) to an Orderless-light expression: space separated inputs are all 171 | matched in any order. If the grep backend does not support PCRE lookahead, it'll 172 | only accept 3 space separated inputs to prevent long lookup times, and further 173 | filtering should be done after a second =#=. 174 | 175 | For more information [[https://github.com/minad/consult#asynchronous-search][see here]]. 176 | 177 | ## Marginalia 178 | 179 | | Keybind | Description | 180 | |---------+---------------------------------| 181 | | [[kbd:][M-A]] | Cycle between annotation levels | 182 | 183 | Marginalia annotations for symbols (e.g. [[kbd:][spc h f]] and [[kbd:][spc h v]]) come with extra 184 | information the nature of the symbol. For the meaning of the annotations see 185 | ~marginalia--symbol-class~. 186 | 187 | ## Orderless filtering 188 | When using orderless to filter through candidates, the default behaviour is for 189 | each space separated input to match the candidate as a regular expression or 190 | literally. 191 | 192 | Note that due to this style of matching, pressing tab does not expand the input 193 | to the longest matching prefix (like shell completion), but rather uses the 194 | first matched candidate as input. Filtering further is instead achieved by 195 | pressing space and entering another input. In essence, when trying to match 196 | =foobar.org=, instead of option 1., use option 2.: 197 | 198 | 1. (BAD) Enter ~foo TAB~, completes to =foobar.=, enter ~org RET~ 199 | 2. (GOOD) Enter ~foo spc org RET~ 200 | 201 | Doom has some builtin [[https://github.com/oantolin/orderless#style-dispatchers][style dispatchers]] for more fine-grained filtering, which 202 | you can use to further specify each space separated input in the following ways: 203 | | Input | Description | 204 | |--------------+------------------------------------------| 205 | | ~!foo~ | match without literal input =foo= | 206 | | ~%foo~ or ~foo%~ | perform ~char-fold-to-regexp~ on input =foo= | 207 | | ~`foo~ or ~foo`~ | match input =foo= as an initialism | 208 | | ~=foo~ or ~foo=~ | match only with literal input =foo= | 209 | | ~~foo~ or ~foo~~ | match input =foo= with fuzzy/flex matching | 210 | -------------------------------------------------------------------------------- /docs/install/doom-configuration.md: -------------------------------------------------------------------------------- 1 | # Doom Emacs configuration 2 | 3 | Doom curates a large number of modules, a module being one or more Emacs packages with configuration. 4 | 5 | `~/.config/doom/` contains three configuration files created by the install process. 6 | 7 | * init.el - enable / disable Doom modules 8 | * config.el - elisp configuration, setting variables, etc. 9 | * packages.el - manage specific packages, adding to or overriding packages in the Doom modules 10 | 11 | 12 | ??? HINT "Check parens are balanced in config" 13 | `check-parens` command will check the current buffer for balanced parens (all open parens have a matching close paren) 14 | 15 | 16 | ## Doom modules 17 | 18 | ++spc++ ++"h"++ ++"d"++ ++"m"++ to list the built-in Doom module documentation (NOTE: documentation for some modules can be light or non-existant) 19 | 20 | Edit `.config/doom/init.el` to select modules to be included. 21 | 22 | [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config) has a curated set of modules 23 | 24 | The most useful modules include: 25 | 26 | | Module | Description | 27 | |------------------|-----------------------------------------------| 28 | | (clojure +lsp) | Cider and Clojure Mode | 29 | | lsp | language server support UI | 30 | | (magit +forge) | Rich Git Client with Forge Issue & PR support | 31 | | (docker +lsp) | editing in many places at once | 32 | | multiple-cursors | editing in many places at once | 33 | 34 | 35 | ## Personal information 36 | 37 | ```emacs 38 | (setq auth-sources '("~/.authinfo.gpg") 39 | auth-source-cache-expiry nil) ; default is 7200 (2h) 40 | ``` 41 | 42 | ## buffers 43 | 44 | Set new buffers to open in org-mode rather than fundamntal-mode 45 | 46 | ```emacs 47 | (setq-default major-mode 'org-mode) 48 | ``` 49 | 50 | 51 | ## Line Numbers 52 | 53 | `display-line-numbers-type` defines the type of line numbers. 54 | 55 | - `nil` consecutive line numbering, 1,2,3,... 56 | - `relative` relative numbers to current line for vim navigation, e.g. `24 j` to jump down 24 lines. 57 | 58 | Set to relative for Vim-style relative numbers, to support jumping lines, e.g. ++2++ ++4++ ++j++ 59 | 60 | ```emacs title="~/.config/doom/config.el" 61 | (setq display-line-numbers-type 'relative) 62 | ``` 63 | 64 | ## Frames 65 | 66 | ++spc++ ++"t"++ ++f++ toggles the current frame to be full screen 67 | 68 | Configure Emacs to always start maximized 69 | 70 | ```emacs title="~/.config/doom/config.el" 71 | (add-to-list 'default-frame-alist '(fullscreen . maximized)) 72 | ``` 73 | 74 | ## Theme 75 | 76 | ++spc++ ++"h"++ ++t++ opens a selection menu of all available themes. Type a theme name or scroll with ++ctrl+"j"++ and ++ctrl+"k"++ 77 | 78 | ++enter++ to select the theme. 79 | 80 | doom-gruvbox theme is configured in [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank} 81 | 82 | ```emacs title="~/.config/doom/config.el" 83 | (setq doom-theme 'doom-gruvbox) 84 | ``` 85 | 86 | ## Font 87 | 88 | ++ctrl+equals++ to increase font size, ++ctrl+minus++ to decrease fault size. 89 | 90 | Practicalli recommends Fira Code font which is a very clear font for source code and also supports ligatures. Fira Code is configured in [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank} 91 | 92 | ![Fira Code font programming ligatures for Clojure](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/fira-code-font-clojure-ligatures.png) 93 | 94 | ```emacs title="~/.config/doom/config.el" 95 | (setq doom-font (font-spec :family "Fira Code" :size 14 :weight 'semi-light)) 96 | ``` 97 | 98 | TODO: set font for big mode ++spc++ ++"t"++ ++"b"++ 99 | 100 | ??? INFO "Doom Font variables" 101 | Doom exposes five (optional) variables for controlling fonts in Doom: 102 | 103 | - `doom-font' -- the primary font to use 104 | - `doom-variable-pitch-font' -- a non-monospace font (where applicable) 105 | - `doom-big-font' -- used for `doom-big-font-mode'; use this for presentations or streaming. 106 | - `doom-unicode-font' -- for unicode glyphs 107 | - `doom-serif-font' -- for the `fixed-pitch-serif' face 108 | 109 | 'C-h v doom-font' for documentation and more examples of what they accept. For example: 110 | 111 | 112 | ## Treemacs 113 | 114 | Preview files when navigating file names in treemacs 115 | 116 | > Not used by practicalli/doom-emacs-config 117 | 118 | ```emacs title=".config/doom/config.el" 119 | ;; Not currently used in practicalli/doom-emacs-config 120 | (map! :map treemacs-mode-map 121 | "" (lambda (&optional arg) (interactive) 122 | (next-line arg) 123 | (save-selected-window 124 | (treemacs-RET-action))) 125 | "" (lambda (&optional arg) (interactive) 126 | (previous-line arg) 127 | (save-selected-window 128 | (treemacs-RET-action)))) 129 | ``` 130 | 131 | 132 | ## Version control 133 | 134 | Magit Forge will use encrypted developer tokens stored in authinfo.gpg to access GitHub / GitLab API, to manage issues and pull requests. 135 | 136 | ```emacs 137 | (setq auth-sources (list 138 | (concat (getenv "XDG_CONFIG_HOME") "/authinfo.gpg") 139 | "~/.authinfo.gpg")) 140 | ``` 141 | 142 | 143 | ## Format tools 144 | 145 | Markdown 146 | 147 | ++spc++ ++colon++ `+format/buffer` 148 | 149 | ```shell 150 | sudo npm install markdownlint 151 | ``` 152 | 153 | 154 | ### Indent 155 | 156 | TAB with cursor at start of a line will indent the line, any other position on the line it will try to insert a tab 157 | 158 | Configure TAB to always indent the line, no matter the column position 159 | 160 | ```emacs 161 | (setq tab-always-indent 'complete) 162 | ``` 163 | 164 | 165 | ### Whitespace cleanup 166 | 167 | ++spc++ ++"c"++ ++"w"++ deletes whitespace at end of lines 168 | 169 | ++spc++ ++"c"++ ++W++ deletes whitespace at end of lines 170 | 171 | Automating whitespace cleanup seems very limited and requires external format tools which may also use a number of format rules that may or may not be of value. 172 | 173 | ??? WARNING "Format module requires format tools" 174 | Doom does not have the capability to remove whitespace by itself 175 | 176 | Enable the `format` module with the `+onsave` option to call the respective format tool 177 | 178 | ```emacs title=".config/doom/init.el" 179 | (format +onsave) 180 | ``` 181 | 182 | Install the format Command Line tools 183 | 184 | - Prettier - Markdown and others... 185 | 186 | ```shell 187 | sudo npm install --global prettier 188 | ``` 189 | 190 | ??? WARNING "Prettier has very limited Markdown rule configuration" 191 | Prettier only has one configuration option, whether to wrap lines. It is not possible to configure any rules as with MarkdownLint. 192 | 193 | 194 | 195 | ## Docker support 196 | 197 | `(docker +lsp)` for Docker module with LSP support, providing Dockerfile lint and syntax support 198 | 199 | LSP server binary provided by `dockerfile-language-server-nodejs` package 200 | 201 | ```shell 202 | sudo npm install --global dockerfile-language-server-nodejs 203 | ``` 204 | 205 | This module assumes `docker`, `docker-compose` and =docker-machine= binaries are installed and accessible from your PATH. 206 | 207 | 208 | ## Performance tweaks 209 | 210 | Configuration files for doom start with lexical binding which has performance advantages. 211 | 212 | ```emacs title=".config/doom/+clojure.el" 213 | ;;; +clojure.el -*- lexical-binding: t; -*- 214 | ``` 215 | 216 | * [Performance advantages of lexical scope](https://nullprogram.com/blog/2016/12/22/) 217 | -------------------------------------------------------------------------------- /docs/install/evil-configuration.md: -------------------------------------------------------------------------------- 1 | # Evil configuration 2 | 3 | 4 | 5 | ## Map Evil keys 6 | 7 | Key bindings to surround text with parens and other pairs 8 | 9 | ```emacs 10 | (after! evil-surround 11 | (let ((pairs '((?g "$" . "$") 12 | (?h "(" . ")") 13 | (?j "[" . "]") 14 | (?k "{" . "}") 15 | (?l "<" . ">") 16 | (?ø "'" . "'") 17 | (?æ "\"" . "\"")))) 18 | (prependq! evil-surround-pairs-alist pairs) 19 | (prependq! evil-embrace-evil-surround-keys (mapcar #'car pairs)))) 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /docs/install/index.md: -------------------------------------------------------------------------------- 1 | # Install Doom Emacs 2 | 3 | [Install prerequisites: Emacs, Java 17, Clojure CLI and Command Line tools ](pre-install.md){.md-button} 4 | 5 | 1. [Clone Doom Emacs](#clojure-doom-emacs) to `~/.config/emacs` 6 | 2. [Clone practicalli/doom-emacs-config configuration](#clone-practicalli-doom-emacs-configuration) to add common modules for Clojure development and related languages. Or edit `~/.config/doom/init.el` and define the Doom modules required. Follow the [Doom configuration section](doom-configuration/) for details. 7 | 3. [optional] [Install Fira Code font](#install-fira-code-font) (change `dotspacemacs-default-font` to a name of a font on your operating system in `.spacemacs.d/init.el` in step 4) 8 | 4. 9 | 10 | ## Clone Doom Emacs 11 | 12 | Use your favourite git client or the following command in a terminal window to clone Spacemacs and then run the Doom Emacs install script 13 | 14 | === "Free Desktop XDG config" 15 | ``` 16 | git clone https://github.com/hlissner/doom-emacs ~/.config/emacs 17 | 18 | ~/.config/emacs/bin/doom install 19 | ``` 20 | 21 | `~/.config/doom` directory will be created by the install and contain the default configuration. 22 | 23 | 24 | === "Classic config" 25 | ``` 26 | git clone https://github.com/hlissner/doom-emacs ~/.emacs.d 27 | 28 | ~/.emacs.d/bin/doom install 29 | ``` 30 | 31 | ### Add Doom command to path 32 | 33 | Doom provides tools to check the user configuration, `doom doctor`, and to update modules, ``Either add `.config/emacs/bin` to the system path 34 | 35 | 36 | === "Symbolic link" 37 | Create a symbolic link called doom from the local user bin directory to the Doom Emacs installation bin/doom file 38 | ```shell 39 | ln -s ~/.config/emacs/bin/doom .local/bin/doom 40 | ``` 41 | 42 | === "Export PATH" 43 | In the user shell configuration file (`~/.bashrc`, `~/.zshenv`), export the PATH environment variable and include the path to the Doom Emacs install bin directory 44 | ```shell 45 | export PATH=$PATH:$HOME/.config/emacs/bin 46 | ``` 47 | 48 | 49 | ## Clone Practicalli Doom configuration 50 | 51 | Remove the autogenerated configuration from the Doom install 52 | 53 | ```shell 54 | mv ~/.config/doom ~/.config/doom-backup 55 | ``` 56 | 57 | Clone [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config) or first create a fork and clone that fork 58 | 59 | === "Free Desktop XDG config" 60 | Using SSH 61 | ```shell 62 | git clone git@github.com:practicalli/doom-emacs-config.git ~/.config/doom 63 | ``` 64 | 65 | 66 | Using HTTPS 67 | ```shell 68 | git clone https://github.com/practicalli/doom-emacs-config ~/.config/doom 69 | ``` 70 | 71 | === "Classic config" 72 | Using SSH 73 | ```shell 74 | git clone git@github.com:practicalli/doom-emacs-config.git ~/.config/doom 75 | ``` 76 | 77 | Using HTTP 78 | ```shell 79 | git clone https://github.com/practicalli/doom-emacs-config ~/.config/doom 80 | ``` 81 | 82 | ## Check & Update Doom Emacs 83 | 84 | `doom doctor` diagnoses common issues with your environment and setup, and may offer clues about what is wrong. 85 | 86 | `doom sync` ensures Emacs packages are installed, orphaned packages are removed and autoloads/cache files are up to date. 87 | 88 | ```shell 89 | doom doctor && doom sync 90 | ``` 91 | 92 | ??? HINT "doom doctor - successful output example" 93 | ![Doom doctor - successful output](https://raw.githubusercontent.com/practicalli/graphic-design/live/doom-emacs/doom-doctor-output-green.png) 94 | 95 | 96 | ## Install Fira Code font 97 | 98 | [Install Fira Code](https://github.com/tonsky/FiraCode/wiki/Installing){target=_blank .md-button} 99 | 100 | [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config) uses Fira Code, a mono-spaced font designed for source code and includes [ligatures](https://github.com/tonsky/FiraCode#whats-in-the-box) and [many other features](https://github.com/tonsky/FiraCode#whats-in-the-box). 101 | 102 | ![Fira Code font - ligatures for Emacs and Clojure code](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/fira-code-font-clojure-ligatures.png) 103 | 104 | !!! TIP "Use a different font with practicalli/doom-emacs-config" 105 | To use a different font when using the [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config), edit `.config/doom/config.el` and update the value for `doom-font` and any variations of fonts required 106 | ```emacs 107 | (setq doom-font (font-spec :family "Fira Code" :size 14) 108 | doom-big-font (font-spec :family "Fira Code" :size 24) 109 | doom-variable-pitch-font (font-spec :family "Ubuntu" :size 16)) 110 | ``` 111 | 112 | 113 | ## Language Servers 114 | 115 | Some languages support Language Server Protocol to provide static analysis of code structure and provide live linting and other features. Each language will require installation of its own language server, most often as a nodejs package. 116 | 117 | ``` 118 | sudo npm install --global vscode-json-languageserver dockerfile-language-server-nodejs vscode-html-languageservice vscode-css-languageservice yaml-language-server 119 | ``` 120 | 121 | Or install a language server for the specific language 122 | 123 | === "Clojure" 124 | [clojure-lsp.io](https://clojure-lsp.io/) provides the language server implementation for Clojure. Follow the [relevant operating system install guide](https://clojure-lsp.io/installation/) 125 | 126 | On Linux machines, Practicalli recommends installing the [latest clojure-lsp release](https://github.com/clojure-lsp/clojure-lsp/releases) to `~/.local/bin/` 127 | 128 | === "JSON" 129 | Add `(json +lsp)` doom module in `.config/doom/init.el` and install the JSON language server 130 | ``` 131 | sudo npm install --global yaml-language-server 132 | ``` 133 | 134 | === "Docker" 135 | Add `(docker +lsp)` doom module in `.config/doom/init.el` and install the Dockerfile language server 136 | ``` 137 | sudo npm install --global dockerfile-language-server-nodejs 138 | ``` 139 | 140 | === "Web" 141 | Add `(web +lsp)` doom module in `.config/doom/init.el` and install the HTML and CSS language servers 142 | ``` 143 | sudo npm install --global vscode-html-languageservice vscode-css-languageservice 144 | ``` 145 | 146 | === "YAML" 147 | Add `(yaml +lsp)` doom module in `.config/doom/init.el` and install the YAML language server 148 | ``` 149 | sudo npm install --global yaml-language-server 150 | ``` 151 | 152 | 153 | ## Doom Emacs ready 154 | 155 | Doom Emacs is and ready to help you take on the world. Run emacs from a desktop launcher or on the command line: 156 | 157 | ```shell 158 | emacs 159 | ``` 160 | !!! WARNING "Native compliation initial high cpu use" 161 | On first running Emacs after Doom install added packages, the elisp code will be compiled to native binaries. The compilation will use considerable CPU resources. 162 | 163 | If you already know how to use Doom Emacs, jump to the [Clojure Projects section](/doom-emacs/clojure-development/), otherwise look through the [Doom Basics](/doom-emacs/basics/) to learn how to use Vim style editing and work with files, buffers and windows. 164 | 165 | 166 | -------------------------------------------------------------------------------- /docs/install/pre-install.md: -------------------------------------------------------------------------------- 1 | # Pre-install 2 | 3 | Spacemacs is a configuration for Emacs, so naturally [Emacs](#install-emacs) should be installed before Spacemacs can be used. 4 | 5 | [Clojure CLI](#install-clojure-cli) should be installed to support Clojure development, along with several supporting development tools. 6 | 7 | [Command Line Tools](#command-line-tools) support searching for files and spell checking. 8 | 9 | 10 | 11 | ## Install Emacs 12 | 13 | ![GNU Emacs logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/logos/emacs-icon.svg){align=right loading=lazy} 14 | 15 | Emacs 28 is recommended as it includes native compilation support and optomised JSON support which is valuable for Language Server Protocol servers. 16 | 17 | Emacs is available for Linux, MacOSX and Windows. The [Spacemacs Readme suggested ways to install Emacs](https://github.com/syl20bnr/spacemacs/tree/develop#emacs) 18 | 19 | ??? INFO "Emacs Version 28 recommended" 20 | Emacs 28 is recommended with native compilation of Elisp, which can have a significant improvement on Emacs package performance. 21 | Emacs 27.1 is the minimum version supported by Practicalli Spacemacs 22 | 23 | 24 | === "Ubuntu / Debian" 25 | `apt-cache show emacs` to check available versions of Emacs in the Ubuntu package manager. If version 28 is available, install Emacs using the Ubuntu package manager. 26 | 27 | ```bash 28 | sudo apt install emacs 29 | ``` 30 | 31 | Additional versions of Emacs are available via the [Ubuntu Emacs Team Personal Package Archive](https://launchpad.net/~ubuntu-elisp/+archive/ubuntu/ppa). 32 | 33 | `sudo apt install emacs-snapshot` package to use the latest nightly build of Emacs, although be aware that some things may break. 34 | 35 | 36 | ??? HINT "Build Emacs 28 from source" 37 | [Building Emacs 28 from source code on Ubuntu](https://practical.li/blog/posts/build-emacs-28-on-ubuntu/) is relatively straight forward task, although it will take a little time to compile. Building Emacs allows customisation of some features, such as native compilatin of elisp to enhance the performance of Emacs. 38 | 39 | 40 | === "Homebrew / MacOSX" 41 | [Emacs Plus](https://github.com/d12frosted/homebrew-emacs-plus) from Homebrew provides many options, including native compilation and Spacemacs Icon for application launchers. 42 | 43 | ``` 44 | brew tap d12frosted/emacs-plus` 45 | brew install emacs-plus@28 --with-native-comp --with-spacemacs-icon 46 | ``` 47 | 48 | Emacs.app is installed to: `/usr/local/opt/emacs-plus@28` 49 | 50 | Optionally run Emacs plus as a service 51 | ``` 52 | brew services start d12frosted/emacs-plus/emacs-plus@28 53 | ``` 54 | 55 | Run `emacs` 56 | 57 | Get a hot cup of something as Emacs native compilation compiles all the things. 58 | 59 | 60 | > The [Spacemacs README lists other options for MacOSX](https://github.com/syl20bnr/spacemacs#macos). 61 | 62 | 63 | === "Windows" 64 | Download Emacs-28.2 from the [GNU repository](http://ftp.gnu.org/gnu/emacs/windows/emacs-26) and extract the zip file to `%AppData%/local/Programs/emacs`. 65 | 66 | Alternatively, if you are using the [Chocolatey package manager](https://chocolatey.org/){target=_blank} then install [Emacs version 28](https://chocolatey.org/packages/emacs){target=_blank} 67 | 68 | Add the Emacs directory to the `PATH` variable in your user account environment variables. 69 | 70 | To start Emacs run the command `runemacs.exe`. You can also pin this to the start menu or task bar. 71 | 72 | ??? HINT "Access to common Unix tools" 73 | Command line tools, such as `diff`, are used by Emacs. To have these command line tools available in Windows, install Emacs as above but then run emacs from a Unix shell such as [GitBash](https://git-scm.com/){target=_blank}. 74 | 75 | 76 | === "Msys2" 77 | Install Emacs (64bits build) with the following: 78 | 79 | ``` 80 | pacman -S mingw-w64-x86_64-emacs 81 | ``` 82 | 83 | 84 | ## Install Clojure CLI 85 | 86 | ![Clojure logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/logos/clojure-logo.svg){align=right loading=lazy} 87 | 88 | [Practicalli Clojure Install Guide](https://practical.li/clojure/install/){target=_blank .md-button } 89 | 90 | Clojure CLI provide a simple and configurable way to: 91 | 92 | * Run Clojure programs and tools 93 | * Run an interactive REPL (Read-Eval-Print Loop) and evaluate Clojure expressions, usually with a [Clojure aware editor](https://practical.li/clojure/clojure-editors/) 94 | * Managing dependencies (via tools.deps) from Maven and Git repositories 95 | 96 | Using community tools on top of Clojure CLI tools provides tasks to create, develop, build and deploy Clojure applications and services 97 | 98 | Follow the [Practicalli Clojure Install Guide](https://practical.li/clojure/install/) to install Clojure and supporting tools. 99 | 100 | 101 | ## Command Line Tools 102 | 103 | ![Command Line icon](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/terminal-emulator-green-screen.svg){align=right loading=lazy} 104 | 105 | Emacs uses several external command line tools. There are some very efficient search tools that are recommended (ripgrep, silver searcher). 106 | 107 | Consider installing these tools to enhance your Spacemacs experience. 108 | 109 | 110 | ### spell check 111 | 112 | [spell-checking layer](https://develop.spacemacs.org/layers/+checkers/spell-checking/README.html) in Spacemacs supports ispell, hunspell, and aspell command line tools. Aspell is the recommended spell checking tool. 113 | 114 | === "Ubuntu / Debian" 115 | Aspell binary is usually installed on Unix systems by default. Use `sudo apt instal aspell` if not already present. 116 | 117 | === "Homebrew" 118 | `brew install aspell` 119 | 120 | === "Manual" 121 | [Aspell Install](http://aspell.net/){.md-button target=_blank} 122 | 123 | 124 | ### Text search 125 | 126 | Search text buffers uses an external search tool. Although grep is available in most operating systems, ripgrep (rg) or silver-searcher (ag) offer far greater performance and have more search options. 127 | 128 | `dotspacemacs-search-tools '("rg" "ag" "pt" "ack" "grep")` in the Spacemacs configuration defines the order of preference for the search tool to use. 129 | 130 | [ripgrep (rg)](https://github.com/BurntSushi/ripgrep){.md-button target=_blank} 131 | [Silver Searcher (ag)](https://github.com/ggreer/the_silver_searcher){.md-button target=_blank} 132 | 133 | 134 | ### Find files 135 | 136 | ++spc++ ++"p"++ opens the projectile menu for finding files relative to the current project. Projectile uses the external command line tool `find` to index files that are not part of a version controlled project (using `git` for projects versioned with Git). 137 | 138 | `fd` is an external command line binary that is faster than the `find` command. If installed, projectile will automatically use `fd` instead of `find` 139 | 140 | [fd install instructions by operating system ](https://github.com/sharkdp/fd#installation){.md-button target=_blank} 141 | 142 | 143 | ### helm-locate 144 | 145 | The `locate` binary is used by ++spc++ ++"f"++ ++l++ (`helm-locate`) to find files and directories on the operating system file space. 146 | 147 | `helm-locate` is the fastest way to search for files across the whole file space on your computer as it uses the updatedb database. If a file was very recently added to the file system, run `sudo updatedb` to ensure all files are in the database. 148 | 149 | === "Ubuntu / Debian" 150 | ```shell 151 | sudo apt install locate 152 | ``` 153 | 154 | === "Homebrew / MacOSX" 155 | [findutils Homebrew findutils](https://formulae.brew.sh/formula/findutils){.md-button target=_blank} 156 | ```shell 157 | brew install findutils 158 | ``` 159 | -------------------------------------------------------------------------------- /docs/introduction/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Practicalli 2 | 3 | Practicalli books are written in markdown and use MkDocs to generate the published website via a GitHub workflow. MkDocs can also run a local server using the `make docs` target from the `Makefile` 4 | 5 | By submitting content ideas and corrections you are agreeing they can be used in this workshop under the [Creative Commons Attribution ShareAlike 4.0 International license](https://creativecommons.org/licenses/by-sa/4.0/). Attribution will be detailed via [GitHub contributors](https://github.com/practicalli/doom-emacs/graphs/contributors). 6 | 7 | All content and interaction with any persons or systems must be done so with respect and within the Practicalli Code of Conduct. 8 | 9 | ## Book status 10 | 11 | [![GitHub issues](https://img.shields.io/github/issues/practicalli/doom-emacs?label=content%20ideas&logo=github)](https://img.shields.io/github/issues/practicalli/doom-emacs?label=content%20ideas&logo=github){target=_blank} 12 | [![GitHub commit activity](https://img.shields.io/github/commit-activity/y/practicalli/doom-emacs?label=commits&logo=github)](https://img.shields.io/github/commit-activity/y/practicalli/doom-emacs?label=commits&logo=github){target=_blank} 13 | [![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/practicalli/doom-emacs?label=pull%20requests&logo=github)](https://img.shields.io/github/issues-pr-raw/practicalli/doom-emacs?label=pull%20requests&logo=github){target=_blank} 14 | 15 | [![MegaLinter](https://github.com/practicalli/doom-emacs/actions/workflows/megalinter.yml/badge.svg)](https://github.com/practicalli/doom-emacs/actions/workflows/megalinter.yaml){target=_blank} 16 | [![Publish Book](https://github.com/practicalli/doom-emacs/actions/workflows/publish-book.yaml/badge.svg)](https://github.com/practicalli/doom-emacs/actions/workflows/publish-book.yaml){target=_blank} 17 | [![pages-build-deployment](https://github.com/practicalli/doom-emacs/actions/workflows/pages/pages-build-deployment/badge.svg)](https://github.com/practicalli/doom-emacs/actions/workflows/pages/pages-build-deployment){target=_blank} 18 | 19 | ![GitHub contributors](https://img.shields.io/github/contributors/practicalli/doom-emacs?style=for-the-badge&label=github%20contributors) 20 | 21 | ## Submit and issue or idea 22 | 23 | If something doesnt seem quite right or something is missing from the book, please [raise an issue via the GitHub repository](https://github.com/practicalli/clojure/issues){target=_blank} explaining in as much detail as you can. 24 | 25 | **Raising an issue before creating a pull request will save you and the maintainer time**. 26 | 27 | ## Considering a Pull request? 28 | 29 | !!! INFO "Pull Request Commits must be cryptographically signed" 30 | All commits contributed to Practicalli must be signed via a legitimate SSH or GPG key to avoid the risk of commit spoofing. 31 | 32 | [Configure commit signing with SSH key - Practicalli Engineering](https://practical.li/engineering-playbook/source-control/git-configuration/#commit-signing-with-ssh-key){target=_blank .md-button} 33 | 34 | All pull requests must include an entry in CHANGELOG.md or will not be merged. A changelog entry allows the community to follow the changes to the book. 35 | 36 | Each pull request will have a number of CI workflows run against the contribution, checking the format of the content and if a changelog entry has been provided. 37 | 38 | Please keep pull requests small and focused, as they are much quicker to review and easier to accept. Ideally PR's should be for a specific page or at most a section. 39 | 40 | A PR with a list of changes across different sections will be closed without merging as these take considerable time to review. 41 | 42 | Issues such as grammar improvements are typically a sign of a rushed section that requires a rewrite, so a pull request to fix a typeographic error will probably not be merged. Raise an issue, or post a thread in the [:globe_with_meridians: Clojurians Slack #practicall channel](https://clojurians.slack.com/messages/practicalli) 43 | 44 | ## Thank you to everyone that has contributed 45 | 46 | A huge thank you to Rich Hickey and the team at Cognitect for creating and continually guiding the Clojure language. Special thank you to Alex Miller who has provided excellent advice on working with Clojure and the CLI tooling. 47 | 48 | The Clojure community has been highly supportive of everyone using Clojure and I'd like to thank everyone for the feedback and contributions. I would also like to thank everyone that has joined in with the [London Clojurins community](https://www.meetup.com/London-Clojurians/){target=_blank}, [ClojureBridgeLondon](https://clojurebridgelondon.github.io/){target=_blank}, [Clojurians Slack community](http://clojurians.net/){target=_blank}, [Clojurians Zulip](https://clojurians.zulipchat.com/){target=_blank} community and [Clojureverse community](https://clojureverse.org/){target=_blank}. 49 | 50 | Thank you to everyone who sponsors the Practicalli websites and videos and for the [Clojurists Together sponsorship](https://www.clojuriststogether.org/){target=_blank}, it helps me continue the work at a much faster pace. 51 | 52 | Special thanks to [Bruce Durling](https://twitter.com/otfrom){target=_blank} for getting me into Cloure in the first place. 53 | 54 | ![GitHub contributors](https://img.shields.io/github/contributors/practicalli/doom-emacs?style=for-the-badge&label=github%20contributors) 55 | -------------------------------------------------------------------------------- /docs/introduction/repl-workflow.md: -------------------------------------------------------------------------------- 1 | # REPL Driven Development 2 | 3 | ![Clojure repl driven development](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/clojure-repl-workflow-concept.png){loading=lazy} 4 | 5 | !!! Quote "Always be REPL'ing" 6 | Coding without a REPL feels limiting. The REPL provides fast feedback from code as its crafted, testing assumptions and design choices every step of the journey to a solution 7 | - John Stevenson, Practical.li 8 | 9 | Clojure is a powerful, fun and highly productive language for developing applications and services. 10 | The clear language design is supported by a powerful development environment known as the REPL (read, evaluate, print, loop). The REPL gives you instant feedback on what your code does and enables you to test either a single expression or run the whole application (including tests). 11 | 12 | **REPL driven development is the foundation of working with Clojure effectively** 13 | 14 | An effective Clojure workflow begins by running a REPL process. Clojure expressions are written and evaluated immediately to provide instant feedback. The REPL feedback helps test the assumptions that are driving the design choices. 15 | 16 | * Read - code is read by the Clojure reader, passing any macros to the macro reader which converts those macros into Clojure code. 17 | * Evaluate - code is compiled into the host language (e.g. Java bytecode) and executed 18 | * Print - results of the code are displayed, either in the REPL or as part of the application. 19 | * Loop - the REPL is a continuous process that evaluates code, either a single expression or the whole application. 20 | 21 | Design decisions and valuable data from REPL experiments can be codified as [specifications](#data-and-function-specifications) and [unit tests](#test-driven-development-and-repl-driven-development) 22 | 23 | !!! HINT "Practicalli REPL Reloaded Workflow" 24 | The principles of REPL driven development are implemented in practice using the [Practicalli REPL Reloaded Workflow and supporting tooling](https://practical.li/clojure/clojure-cli/repl-reloaded/){target=_blank}. This workflow uses Portal to inspect all evaluation results and log events, hot-load libraries into the running REPL process and reloads namespaces to support major refactor changes. 25 | 26 | ## Evaluating source code 27 | 28 | ![Clojure repl driven development using Clojure aware editor](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/clojure-repl-driven-development-clojure-aware-editor.png){align=right loading=lazy} 29 | 30 | A REPL connected editor is the primary tool for evaluating Clojure code from source code files, displaying the results inline. 31 | 32 | ource code is automatically evaluated in its respective namespace, removing the need to change namespaces in the REPL with (`in-ns`) or use fully qualified names to call functions. 33 | 34 | 35 | !!! HINT "Evaluate Clojure in Practicalli Doom Emacs Config" 36 | `, e f` evaluates the top level form under the cursor 37 | 38 | `, e e` evaluated the expression immediately before the cursor (useful for evaluating nested expressions) 39 | 40 | `, e b` evaluates the whole buffer (expressions within the comment form or prefixed with `#_` reader comment are not evaluated) 41 | 42 |

43 | 44 |

45 | 46 | 47 | !!! Hint Evaluate to Comment for results history 48 | `, e ;` (`cider-eval-defun-to-comment`) evaluates the current form and prints the result under the expression as a comment 49 | 50 | Adding result comment is an effective way to show the expected results of the code design, especially as a journal. 51 | 52 | 53 | ??? HINT "Evaluate Clojure in a Terminal UI REPL" 54 | Entering expressions at the REPL prompt evaluates the expression immediately, returning the result directly underneath 55 | ![Clojure Terminal UI REPL](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/rebel/clojure-repl-rebel-eval-map-function-dark.png#only-dark){loading=lazy} 56 | ![Clojure Terminal UI REPL](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/rebel/clojure-repl-rebel-eval-map-function-light.png#only-light){loading=lazy} 57 | 58 | ## Rich Comment blocks - living documentation 59 | 60 | The `(comment ,,,)` function wraps code that is only run directly by the developer using a [Clojure aware editor](https://practical.li/clojure/clojure-editors/){target=_blank}. 61 | 62 | Expressions in rich comment blocks can represent how to use the functions that make up the namespace API. For example, starting/restarting the system, updating the database, etc. Expressions provide examples of calling functions with typical arguments and make a project more accessible and easier to work with. 63 | 64 | !!! EXAMPLE "Clojure Rich Comment to manage a service" 65 | ```clojure 66 | (ns practicalli.gameboard.service) 67 | 68 | (defn app-server-start [port] ,,,) 69 | (defn app-server-start [] ,,,) 70 | (defn app-server-restart [] ,,,) 71 | 72 | (defn -main 73 | "Start the service using system components" 74 | [& options] ,,,) 75 | 76 | (comment 77 | (-main) 78 | (app-server-start 8888) 79 | (app-server-stop) 80 | (app-server-restart 8888) 81 | 82 | (System/getenv "PORT") 83 | (def environment (System/getenv)) 84 | (def system-properties (System/getProperties)) 85 | ) ; End of rich comment block 86 | ``` 87 | 88 | Rich comment blocks are very useful for rapidly iterating over different design decisions by including the same function but with different implementations. Hide [clj-kondo linter](https://practical.li/clojure/clojure-cli/install/code-analysis.html){target=_blank} warnings for redefined vars (`def`, `defn`) when using this approach. 89 | 90 | ```clojure 91 | ;; Rich comment block with redefined vars ignored 92 | #_{:clj-kondo/ignore [:redefined-var]} 93 | (comment 94 | (defn value-added-tax [] 95 | ;; algorithm design - first idea) 96 | 97 | (defn value-added-tax [] 98 | ;; algorithm design - second idea) 99 | 100 | ) ;; End of rich comment block 101 | ``` 102 | 103 | The "Rich" in the name is an honourary mention to Rich Hickey, the author and benevolent dictator of Clojure design. 104 | 105 | ## Design Journal 106 | 107 | A journal of design decisions makes the code easier to understand and maintain. Code examples of design decisions and alternative design discussions are captured, reducing the time spent revisiting those discussions. 108 | 109 | Journals simplify the developer on-boarding processes as the journey through design decisions are already documented. 110 | 111 | A Design Journal is usually created in a separate namespace, although it may start as a rich comment at the bottom of a namespace. 112 | 113 | A journal should cover the following aspects 114 | 115 | * Relevant expressions use to test assumptions about design options. 116 | * Examples of design choices not taken and discussions why (saves repeating the same design discussions) 117 | * Expressions that can be evaluated to explain how a function or parts of a function work 118 | 119 | The design journal can be used to create meaningful documentation for the project very easily and should prevent time spent on repeating the same conversations. 120 | 121 | !!! HINT "Example design journal" 122 | [Design journal for TicTacToe game using Reagent, ClojureScript and Scalable Vector Graphics](https://github.com/practicalli-john/tictactoe-reagent/blob/master/src/tictactoe_reagent/core.cljs#L124){target=_blank} 123 | 124 | ## Viewing data structures 125 | 126 | Pretty print shows the structure of results from function calls in a human-friendly form, making it easier for a developer to parse and more likely to notice incorrect results. 127 | 128 | ++comma++ ++"e"++ ++"p"++ on the Clojure menu has several commands to Pretty Print data structure results when evaluating code. 129 | 130 | ++comma++ ++"d"++ ++"v"++ is the Cider Inspect menu for paging through very large data sets and navigate nested data structures in detail. 131 | 132 | ![Clojure - viewing large data sets](https://raw.githubusercontent.com/practicalli/graphic-design/live/editors/spacemacs/screenshots/spacemace-clojure-inspect-java-lang-persistentvector.png) 133 | 134 | ++comma++ ++"d"++ is the Cider debug menu which can inspect view intermediate values and data structures during the debugging of Clojure function calls. 135 | 136 | 137 | 138 | Tools to view and navigate code 139 | 140 | * [:fontawesome-solid-book-open: Cider inspector](https://practical.li/spacemacs/evaluating-clojure/inspect/){target=_blank} is an effective way to navigate nested data and page through large data sets. 141 | * [:fontawesome-solid-book-open: Portal Inspector](https://practical.li/clojure/clojure-tools/data-inspector/portal){target=_blank} to visualise many kinds of data in many different forms. 142 | 143 | ![Portal - view and navigate Clojure data and event logs](https://raw.githubusercontent.com/practicalli/graphic-design/live/portal/portal-data-browser-example.png) 144 | 145 | ## Code Style and idiomatic Clojure 146 | 147 | Clojure aware editors should automatically apply formatting that follows the [:globe_with_meridians: Clojure Style guide](https://github.com/bbatsov/clojure-style-guide){target=_blank}. 148 | 149 | Live linting with [clj-kondo](:fontawesome-brands-github: } suggests common idioms and highlights a wide range of syntax errors as code is written, minimizing bugs and therefore speeding up the development process. 150 | 151 | ![Clojure code static analysis for live linting](https://raw.githubusercontent.com/practicalli/graphic-design/live/spacemacs/screenshots/spacemacs-clojure-live-linting-flycheck-errors-light.png#only-light) 152 | ![Clojure code static analysis for live linting](https://raw.githubusercontent.com/practicalli/graphic-design/live/spacemacs/screenshots/spacemacs-clojure-live-linting-flycheck-errors-dark.png#only-dark) 153 | 154 | !!! INFO "Clojure LSP is build on top of clj-kondo" 155 | [:fontawesome-solid-book-open: Clojure LSP](https://practical.li/clojure/clojure-editors/clojure-lsp/){target=_blank} uses clj-kondo static analysis to provide a standard set of development tools (format, refactor, auto-complete, syntax highlighting, syntax & idiom warnings, code navigation, etc). 156 | 157 | Clojure LSP can be used with any Clojure aware editor that provides an LSP client, e.g. [:fontawesome-solid-book-open: Spacemacs](https://practical.li/spacemacs/install-spacemacs/clojure-lsp/){target=_blank}, [:fontawesome-solid-book-open: Doom Emacs](https://practical.li/doom-emacs/install/clojure-configuration/#clojure-cli){target=_blank}, [:fontawesome-solid-book-open: Neovim](https://practical.li/neovim/repl-driven-development/){target=_blank}, VSCode. 158 | 159 | !!! INFO "Clojure Style Guide" 160 | The [:globe_with_meridians: Clojure Style guide](https://github.com/bbatsov/clojure-style-guide){target=_blank} provides examples of common formatting approaches, although the development team should decide which of these to adopt. Emacs `clojure-mode` will automatically format code and so will Clojure LSP (via cljfmt). These tools are configurable and should be tailored to the teams standard. 161 | 162 | ## Data and Function specifications 163 | 164 | [:fontawesome-solid-book-open: Clojure spec](https://practical.li/clojure/clojure-spec/){target=_blank} is used to define a contract on incoming and outgoing data, to ensure it is of the correct form. 165 | 166 | As data structures are identified in REPL experiments, create data specification to validate the keys and value types of that data. 167 | 168 | ```clojure 169 | ;; --------------------------------------------------- 170 | ;; Address specifications 171 | (spec/def ::house-number string?) 172 | (spec/def ::street string?) 173 | (spec/def ::postal-code string?) 174 | (spec/def ::city string?) 175 | (spec/def ::country string?) 176 | (spec/def ::additional string?) 177 | 178 | (spec/def ::address ; Composite data specification 179 | (spec/keys 180 | :req-un [::street ::postal-code ::city ::country] 181 | :opt-un [::house-number ::additional])) 182 | ;; --------------------------------------------------- 183 | ``` 184 | 185 | As the public API is designed, specifications for each functions arguments are added to validate the correct data is used when calling those functions. 186 | 187 | [:fontawesome-solid-book-open: Generative testing](https://practical.li/clojure/clojure-spec/generative-testing/){target=_blank} provides a far greater scope of test values used incorporated into unit tests. Data uses clojure.spec to randomly generate data for testing on each test run. 188 | 189 | ## Test Driven Development and REPL Driven Development 190 | 191 | ![Clojure REPL driven development (RDD) and Test Driven Development (TDD)](https://raw.githubusercontent.com/practicalli/graphic-design/live/clojure/repl-tdd-flow.png){align=right loading=lazy} 192 | 193 | Test Driven Development (TDD) and REPL Driven Development (RDD) complement each other as they both encourage incremental changes and continuous feedback. 194 | 195 | > Test Driven Development fits well with Hammock Time, as good design comes from deep thought 196 | 197 | * RDD enables rapid design experiments so different approaches can easily and quickly be evaluated . 198 | * TDD focuses the results of the REPL experiments into design decisions, codified as unit tests. These tests guide the correctness of specific implementations and provide critical feedback when changes break that design. 199 | 200 | [:fontawesome-solid-book-open: Unit tests](https://practical.li/clojure/testing/unit-testing/){target=_blank} should support the public API of each namespace in a project to help prevent regressions in the code. Its far more efficient in terms of thinking time to define unit tests as the design starts to stabilize than as an after thought. 201 | 202 | `clojure.test` library is part of the Clojure standard library that provides a simple way to start writing unit tests. 203 | 204 | [:fontawesome-solid-book-open: Clojure spec](https://practical.li/clojure/clojure-spec/){target=_blank} can also be used for generative testing, providing far greater scope in values used when running unit tests. Specifications can be defined for values and functions. 205 | 206 | Clojure has a number of [:fontawesome-solid-book-open: test runners](https://practical.li/clojure/testing/test-runners/){target=_blank} available. Kaocha is a test runner that will run unit tests and function specification checks. 207 | 208 | !!! Hint "Automate local test runner" 209 | Use [:fontawesome-solid-book-open: kaocha test runner](https://practical.li/clojure/testing/test-runners/kaocha-test-runner/){target=_blank} in watch mode to run tests and specification check automatically (when changes are saved) 210 | ```bash 211 | clojure -X:test/watch 212 | ``` 213 | 214 | ## Continuous Integration and Deployment 215 | 216 | Add a [:fontawesome-solid-book-open: continuous integration service](https://practical.li/clojure/continuous-integration/){target=_blank} to run tests and builds code on every shared commit. Spin up testable review deployments when commits pushed to a pull request branch, before pushing commits to the main deployment branch, creating an effective pipeline to gain further feedback. 217 | 218 | - [:globe_with_meridians: CircleCI](https://practical.li/clojure/continuous-integration/circle-ci/){target=_blank} provides a simple to use service that supports Clojure projects. 219 | - [:globe_with_meridians: GitHub Workflows](https://docs.github.com/en/actions/using-workflows){target=_blank} and [GitHub actions marketplace](https://github.com/marketplace?type=actions){target=_blank} to quickly build a tailored continuous integration service, e.g. [Setup Clojure GitHub Action](https://github.com/marketplace/actions/setup-clojure){target=_blank}. 220 | - [:globe_with_meridians: GitLab CI](https://docs.gitlab.com/ee/ci/introduction/index.html){target=_blank} 221 | 222 | ![Continuous Integration](https://raw.githubusercontent.com/practicalli/graphic-design/live/continuous-integration/continuous-integration-overview.svg) 223 | 224 | ## Live Coding with Data - Stuart Halloway 225 | 226 | There are few novel features of programming languages, but each combination has different properties. The combination of dynamic, hosted, functional and extended Lisp in Clojure gives developers the tools for making effective programs. The ways in which Clojure's unique combination of features can yield a highly effective development process. 227 | 228 | Over more than a decade we have developed an effective approach to writing code in Clojure whose power comes from composing many of its key features. As different as Clojure programs are from e.g. Java programs, so to can and should be the development experience. You are not in Kansas anymore! 229 | 230 | This talk presents a demonstration of the leverage you can get when writing programs in Clojure, with examples, based on my experiences as a core developer of Clojure and Datomic. 231 | 232 |

233 | 234 |

235 | -------------------------------------------------------------------------------- /docs/introduction/spacemacs-to-doom.md: -------------------------------------------------------------------------------- 1 | # Migrate from Spacemacs to Doom Emacs 2 | 3 | The major differences between Spacemacs and Doom Emacs 4 | 5 | * Key bindings 6 | * Completion framework (vertico rather than helm) 7 | * Spacemacs added touches (Doom has a minimal approach) 8 | 9 | 10 | ## Key bindings 11 | 12 | [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank .md-button} 13 | 14 | [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank} changes many Doom Emacs key bindings to Spacemacs bindings to easy usability of Doom Emacs. The more familiar the key binding experience, the simpler it is to adopt Doom Emacs. 15 | 16 | Not all key bindings have been changed and some of the Doom Emacs defaults are adopted (either because they feel easy to adopt or it is not clear how to change them effectively) 17 | 18 | ## Doom Vim-style bindings 19 | 20 | Doom key bindings tend to follow vim-style movement for the basic operation of Emacs 21 | 22 | ++spc++ ++colon++ for `M-x` to show a list of alll Emacs commands 23 | 24 | ++spc++ ++"w"++ ++"s"++ / ++"v"++ to split a window horizontally / vertical split 25 | 26 | ++spc++ ++"w"++ ++"h"++ / ++"j"++ / ++"k"++ / ++"l"++ to move cursor to window left, down, up right (with captial versions moving the window rather than cursor) 27 | 28 | 29 | ### Major changes 30 | 31 | The [+bindings.el configuration file](https://github.com/practicalli/doom-emacs-config/blob/main/%2Bbindings.el) makes changes to the general use of Doom Emacs 32 | 33 | ++comma++ is mapped as the local leader, ++spc++ remains the leader key (common to both Doom and Spacemacs) 34 | 35 | ++spc++ ++tab++ bound to toggle to last buffer 36 | 37 | ++spc++ ++"l"++ replaces ++spc++ ++tab++ as the workspace menu, ++spc++ ++"l"++ ++tab++ added to toggle to last workspace 38 | 39 | ++spc++ ++"b"++ ++"h"++ added to jump to home buffer 40 | 41 | ++spc++ ++spc++ used as ++meta+"x"++ although the default ++spc++ ++colon++ Doom Emacs binding is kept 42 | 43 | ### File diff 44 | 45 | `SPC D` is the Spacemacs diff menu 46 | 47 | Doom has no menu for diff that I can find, although there are a few Emacs key bindings 48 | 49 | `SPC d` menu provides key bindings for diff, ediff, ediff3, vc-root-diff and vc-diff. Menu included in [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank} 50 | 51 | 52 | ### Magit Status 53 | 54 | ++spc++ ++"g"++ ++"s"++ remaped to Magit Status buffer, although Doom default binding ++spc++ ++"g"++ ++"s"++ is kept 55 | 56 | Doom bindings that are different to Spacemacs and have not been changed in [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config){target=_blank} 57 | 58 | `ZZ` to close and commit message and create a commit (Spaceamcs `,,`) 59 | 60 | `ZQ` to cancel the commit message (Spaceamcs `,k`) 61 | 62 | 63 | ## Spacemacs added touches 64 | 65 | Things added in Spacemacs not available (or not the same) in Doom Emacs 66 | 67 | 68 | ### Visual select 69 | 70 | Spacemacs: 71 | 72 | `SPC v` to select and additional `v` to grow selection, `V` to shrink selection 73 | 74 | Doom: 75 | Use `o` to toggle between ends of selection and grow using vim motions 76 | 77 | > TODO: discover other options and identify if there is a similar approach to Spacemacs `SPC v` 78 | 79 | 80 | ## Paste 81 | 82 | Spacemacs: 83 | 84 | `p` shows the paste transient state menu, allowing for cycling the kill ring and pasting different values 85 | 86 | 87 | Doom: 88 | `p M-y` will paste the current value and use yank-pop to cycle through the kill ring 89 | 90 | `SPC i y` inserts a value from the kill ring, showing a popup list of the history 91 | 92 | 93 | ## Whitespace clean up 94 | 95 | Spacemacs can be configured to automattically remove extra whitespace when saving a file. 96 | 97 | Doom: ++spc++ ++"c"++ ++"w"++ key binding removes extra whitespace 98 | 99 | > TODO: automate whitespace removal on file save 100 | -------------------------------------------------------------------------------- /docs/introduction/why-doom-emacs.md: -------------------------------------------------------------------------------- 1 | # Why Doom Emacs 2 | 3 | Practicalli is evaluating Doom Emacs after many years of using Spacemacs (which is still the main Emacs configuration used) 4 | 5 | Reasons to select doom to date: 6 | 7 | - Experience feels closer to using Neovim, so may be more of a bridge between Emacs and Neovim (help with adoption of Conjure) 8 | - Vertico completion seems comparible to the features regularly used in other tools (Helm, Ivy) 9 | - Package mangager pins specific versions of packages, so potentially more stability. Managing versions of packages seems a litle simpler in Doom, although its only a small difference 10 | - Minimal set of features and an optomised dashboard (similar to Neovim), so perception of faster start up, although saved session needs to be restored after startup. 11 | - Startup speed - a few seconds to start up Emacs is perfectly fine for the Practicalli workflow, where Emacs typically stays running for weeks or months 12 | 13 | 14 | ## Spacemacs or Emacs Doom Configuations 15 | 16 | Spacemacs and Doom Emacs are both open source projects that provide a large amount of common configuration in an easy to use way (typically with little or no Emacs Lisp knowledge required). 17 | 18 | Spacemacs includes far greater number of commands in its default install (via Emacs packages) and has far greater depth to its documentation. 19 | 20 | Doom Emacs contains only the essentials and documentation can be quite sparse in many places, so more searching and help from the community may be required. Additional Emacs Lisp seems to be more prevelant in Doom Emacs. 21 | 22 | There are a nuber of common features between the two configurations: 23 | 24 | - completion frameworks: Spacemacs uses Helm and Doom Emacs uses Vertico to achieve a common set of features (Helm has a greater number of feactures although they share common core) 25 | - projectile project management 26 | - Package abstraction: Spacemacs layers and Doom modules are used over individual Emacs packages 27 | - package manager (Spacemacs: packages.el, Doom: straight.el) 28 | - modelines and themes: Practicalli uses the same modeline and theme for Spacemacs and Doom Emacs 29 | 30 | 31 | ## Migrating from Spacemacs 32 | 33 | Challenging areas when adopting Doom Emacs initially 34 | 35 | 1. key bindings (mnemonic and consistent key bindings used in Spacemacs are not consistent in Doom, although [practicalli/doom-emacs-config](https://github.com/practicalli/doom-emacs-config) adds back many of the most common Spacemacs key bindings. 36 | 2. minimla features by default - Doom Emacs is minimal by design although contains modules (comparable to Spacemacs layers) that are easily added to greatly increase features 37 | 3. learning the different tools that come with Doom (vertico, multiedit, etc) - similar features are provided by different modules and therefore different Emacs packages 38 | 4. Documentation is sparse - built-in docs are good where they have been added, although many modules are undocumented and require investigation of the underlying package documentation 39 | 40 | 41 | ## Is Doom faster than other Emacs configurations 42 | 43 | Startup time was specifically optomised in Doom Emacs and it only opens a minimal dashboard buffer, giving an experience comparable to Neovim. Session state is not loaded by default when starting Emacs, although there is a command on the dashboard to restore the session. 44 | 45 | Factor in the restor of state in startup time, there is very little difference between a default install of Doom Emacs or Spacemacs. 46 | 47 | Practicalli hasnt experienced a noticable performance difference with Doom, as the vast majority of code is in the shared packages that are used by Doom and other projects. 48 | 49 | Any configuration that is adopted will be slow to use initially, especially if it is unfamiliar. Before changing the key bindings I found Doom slower to use as it does not provide a full set of mnemonic key bindings I was used to and was therefore less intuitive to used compared to Spacemacs. 50 | 51 | The [Doom Emacs Clojure module key bindings](https://github.com/hlissner/doom-emacs/blob/develop/modules/lang/clojure/README.org) have been reboud in by Practicalli to extend the commands available. 52 | 53 | !!! QUOTE 54 | The slowest part of the workflow is the person operating the tool. When interation with a tool doesnt flow smoothly, the speed of the tool becomes largely irrelevant - John Stevenson 55 | -------------------------------------------------------------------------------- /docs/introduction/writing-tips.md: -------------------------------------------------------------------------------- 1 | # Writing tips for MkDocs 2 | 3 | Making the docs more engaging using the [mkdocs-material theme reference guide](https://squidfunk.github.io/mkdocs-material/reference/){target=_blank} 4 | 5 | ??? INFO "Configuring Colors" 6 | [Material for MkDocs - Changing the colors](https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/){target=_blank} lists the primary and accent colors available. 7 | 8 | [HSL Color Picker](https://hslpicker.com/) for codes to modify the theme style, overriding colors in `docs/assets/stylesheets/extra.css` 9 | 10 | ## Hypertext links 11 | 12 | Links open in the same browser window/tab by default. 13 | 14 | Add `{target=_blank}` to the end of a link to configure opening in a new tab 15 | 16 | ```markdown 17 | [link text](url){target=_blank} 18 | ``` 19 | 20 | ## Buttons 21 | 22 | Convert any link into a button by adding `{.md-button}` class names to end of the markdown for a link, which uses `.md-button-primary` by default. Include `target=_blank` for buttons with links to external sites. 23 | 24 | ``` 25 | [link text](http://practical.li/blog){.md-button target=_blank} 26 | ``` 27 | 28 | Or specify a different class 29 | 30 | ``` 31 | [link text](http://practical.li/blog){.md-button .md-button-primary} 32 | ``` 33 | 34 | Add an icon to the button 35 | 36 | [:fontawesome-brands-github: Practicalli Issues](http://practical.li/blog){ .md-button .md-button-primary } 37 | [:octicons-heart-fill-24: Practicalli Blog](http://practical.li/blog){ .md-button .md-button-primary } 38 | 39 | ```markdown 40 | [:fontawesome-brands-github: Practicalli Issues](http://practical.li/blog){ .md-button .md-button-primary } 41 | [:octicons-heart-fill-24: Practicalli Blog](http://practical.li/blog){ .md-button .md-button-primary } 42 | ``` 43 | 44 | [Search all supported icons](https://squidfunk.github.io/mkdocs-material/reference/icons-emojis/){target=_blank .md-button} 45 | 46 | ## YouTube video 47 | 48 | Use an iframe element to include a YouTube video, wrapping in a paragraph tag with center alignment to place the video in a centered horizontal position 49 | 50 | ```html 51 |

52 | 53 |

54 | ``` 55 | 56 | > mkdocs material does not have direct support for adding a YouTube video via markdown. 57 | 58 | ## Admonitions 59 | 60 | [Supported admonition types](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#supported-types) 61 | 62 | !!! NOTE 63 | Use `!!!` followed by `NOTE` 64 | 65 | !!! NOTE "Adding a title" 66 | Use `!!!` followed by `NOTE` and a `"title in double quotes"` 67 | 68 | !!! NOTE "" 69 | Shh, no title bar just the text... 70 | Use `!!!` followed by `NOTE` and a `""` empty double quotes 71 | 72 | !!! ABSTRACT 73 | Use `!!!` followed by `ABSTRACT` 74 | 75 | !!! INFO 76 | Use `!!!` followed by `INFO` 77 | 78 | !!! TIP 79 | Use `!!!` followed by `TIP` 80 | 81 | !!! SUCCESS 82 | Use `!!!` followed by `SUCCESS` 83 | 84 | !!! QUESTION 85 | Use `!!!` followed by `QUESTION` 86 | 87 | !!! WARNING 88 | Use `!!!` followed by `WARNING` 89 | 90 | !!! FAILURE 91 | Use `!!!` followed by `FAILURE` 92 | 93 | !!! DANGER 94 | Use `!!!` followed by `DANGER` 95 | 96 | !!! BUG 97 | Use `!!!` followed by `BUG` 98 | 99 | !!! EXAMPLE 100 | Use `!!!` followed by `EXAMPLE` 101 | 102 | !!! QUOTE 103 | Use `!!!` followed by `QUOTE` 104 | 105 | ### Collapsing admonitions 106 | 107 | ??? NOTE 108 | Collapse those admonitions using `???` instead of `!!!` 109 | 110 | ??? NOTE "Replace with a title" 111 | Use `???` followed by `NOTE` and a `"title in double quotes"` 112 | 113 | ???+ NOTE "Expanded by default" 114 | Use `???+`, note the `+` character, followed by `NOTE` and a `"title in double quotes"` 115 | 116 | ### Inline blocks 117 | 118 | Inline blocks of text to make a very specific callout within text 119 | 120 | !!! info inline 121 | 122 | Lorem ipsum dolor sit amet, consectetur 123 | adipiscing elit. Nulla et euismod nulla. 124 | Curabitur feugiat, tortor non consequat 125 | finibus, justo purus auctor massa, nec 126 | semper lorem quam in massa. 127 | 128 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 129 | 130 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 131 | 132 | Adding something to then end of text is probably my favourite 133 | 134 | !!! info inline end 135 | 136 | Lorem ipsum dolor sit amet, consectetur 137 | adipiscing elit. Nulla et euismod nulla. 138 | Curabitur feugiat, tortor non consequat 139 | finibus, justo purus auctor massa, nec 140 | semper lorem quam in massa. 141 | 142 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 143 | 144 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 145 | 146 | ## Code blocks 147 | 148 | Code blocks include a copy icon automatically 149 | 150 | Syntax highlighting in code blocks 151 | 152 | ```clojure 153 | (defn my-function ; Write a simple function 154 | "With a lovely doc-string" 155 | [arguments] 156 | (map inc [1 2 3])) 157 | ``` 158 | 159 | Give the code block a title using `title=""` after the backtics and language name 160 | 161 | ```clojure title="src/practicalli/gameboard.clj" 162 | (defn my-function 163 | "With a lovely doc-string" 164 | [arguments] 165 | (map inc [1 2 3])) 166 | ``` 167 | 168 | We all like line numbers, especially when you can set the starting line 169 | 170 | ```clojure linenums="42" title="src/practicalli/gameboard.clj" 171 | (defn my-function 172 | "With a lovely doc-string" 173 | [arguments] 174 | (map inc [1 2 3])) 175 | ``` 176 | 177 | Add `linenums=42` to start line numbers from 42 onward 178 | 179 | ``` 180 | clojure linenums="42" title="src/practicalli/gameboard.clj" 181 | ``` 182 | 183 | ### Annotations 184 | 185 | Annotations in a code block help to highlight important aspects. Use the comment character for the language followed by a space and a number in brackets 186 | 187 | For example, in a shell code block, use `# (1)` where 1 is the number of the annotation 188 | 189 | Use a number after the code block to add the text for the annotation, e.g. `1.`. Ensure there is a space between the code block and the annotation text. 190 | 191 | ```shell 192 | ls -la $HOME/Downloads # (1) 193 | ``` 194 | 195 | 1. :woman_raising_hand: I'm a code annotation! I can contain `code`, __formatted text__, images, ... basically anything that can be written in Markdown. 196 | 197 | 198 | Code blocks with annotation, add `!` after the annotation number to suppress the `#` character 199 | 200 | ```clojure 201 | (defn helper-function 202 | "Doc-string with description of function purpose" ; (1)! 203 | [data] 204 | (merge {:fish 1} data) 205 | ) 206 | ``` 207 | 208 | 1. Always include a doc-string in every function to describe the purpose of that function, identifying why it was added and what its value is. 209 | 210 | GitHub action example with multiple annotations 211 | 212 | ``` yaml 213 | name: ci # (1)! 214 | on: 215 | push: 216 | branches: 217 | - master # (2)! 218 | - main 219 | permissions: 220 | contents: write 221 | jobs: 222 | deploy: 223 | runs-on: ubuntu-latest 224 | steps: 225 | - uses: actions/checkout@v3 226 | - uses: actions/setup-python@v4 227 | with: 228 | python-version: 3.x 229 | - run: pip install mkdocs-material # (3)! 230 | - run: mkdocs gh-deploy --force 231 | ``` 232 | 233 | 1. You can change the name to your liking. 234 | 235 | 2. At some point, GitHub renamed `master` to `main`. If your default branch 236 | is named `master`, you can safely remove `main`, vice versa. 237 | 238 | 3. This is the place to install further [MkDocs plugins] or Markdown 239 | extensions with `pip` to be used during the build: 240 | 241 | ``` sh 242 | pip install \ 243 | mkdocs-material \ 244 | mkdocs-awesome-pages-plugin \ 245 | ... 246 | ``` 247 | 248 | ### Highlight lines in code blocks 249 | 250 | Add highlight line meta data to a code block after the opening backticks and code block language. 251 | 252 | `hl_lines="2"` highlights line 2 in the codeblock 253 | 254 | ```clojure hl_lines="4 5 6" 255 | (defn my-function 256 | "With a lovely doc-string" 257 | [arguments] 258 | (map 259 | inc 260 | [1 2 3])) 261 | ``` 262 | 263 | ### Embed external files 264 | 265 | `--8<--` in a code block inserts code from a source code file or other text file 266 | 267 | Specify a local file from the root of the book project (the directory containing mkdocs.yml) 268 | 269 | ??? EXAMPLE "Scheduled Version Check GitHub Workflow from source code file" 270 | ```yaml title="scheduled version check" 271 | --8<-- ".github/workflows/scheduled-version-check.yaml" 272 | ``` 273 | 274 | ??? EXAMPLE "Practicalli Project Templates" 275 | ```markdown title="Emacs project configuration - .dir-locals.el" 276 | --8<-- "https://raw.githubusercontent.com/practicalli/project-templates/main/.dir-locals.el" 277 | ``` 278 | 279 | !!! HINT "Code example reuse" 280 | Use an embedded local or external file (URL) when the same content is required in more than one place in the book. 281 | 282 | An effective way of sharing code and configuration mutliple times in a book or across multiple books. 283 | 284 | ## Content tabs 285 | 286 | Create in page tabs that can also be 287 | 288 | Setting up a project 289 | 290 | === "Clojure CLI" 291 | ```shell 292 | clojure -T:project/new :template app :name practicalli/gameboard 293 | ``` 294 | 295 | === "Leiningen" 296 | ```shell 297 | lein new app practicalli/gameboard 298 | ``` 299 | 300 | Or nest the content tabs in an admonition 301 | 302 | !!! INFO "Run a terminal REPL" 303 | 304 | === "Clojure CLI" 305 | ```shell 306 | clojure -T:repl/rebel 307 | ``` 308 | 309 | 310 | === "Leiningen" 311 | ```shell 312 | lein repl 313 | ``` 314 | 315 | ## Diagrams 316 | 317 | Neat flow diagrams 318 | 319 | [Diagrams - Material for MkDocs](https://squidfunk.github.io/mkdocs-material/reference/diagrams/){target=_blank .md-button} 320 | 321 | ``` mermaid 322 | graph LR 323 | A[Start] --> B{Error?}; 324 | B -->|Yes| C[Hmm...]; 325 | C --> D[Debug]; 326 | D --> B; 327 | B ---->|No| E[Yay!]; 328 | ``` 329 | 330 | UML Sequence Diagrams 331 | 332 | ``` mermaid 333 | sequenceDiagram 334 | Alice->>John: Hello John, how are you? 335 | loop Healthcheck 336 | John->>John: Fight against hypochondria 337 | end 338 | Note right of John: Rational thoughts! 339 | John-->>Alice: Great! 340 | John->>Bob: How about you? 341 | Bob-->>John: Jolly good! 342 | ``` 343 | 344 | state transition diagrams 345 | 346 | ``` mermaid 347 | stateDiagram-v2 348 | state fork_state <> 349 | [*] --> fork_state 350 | fork_state --> State2 351 | fork_state --> State3 352 | 353 | state join_state <> 354 | State2 --> join_state 355 | State3 --> join_state 356 | join_state --> State4 357 | State4 --> [*] 358 | ``` 359 | 360 | Class diagrams - not needed for Clojure 361 | 362 | Entity relationship diagrams are handy though 363 | 364 | ``` mermaid 365 | erDiagram 366 | CUSTOMER ||--o{ ORDER : places 367 | ORDER ||--|{ LINE-ITEM : contains 368 | LINE-ITEM { 369 | customer-name string 370 | unit-price int 371 | } 372 | CUSTOMER }|..|{ DELIVERY-ADDRESS : uses 373 | ``` 374 | 375 | 376 | ## Keyboard keys 377 | 378 | Represent key bindings with [Keyboard keys](https://facelessuser.github.io/pymdown-extensions/extensions/keys/#extendingmodifying-key-map-index){target=_blank}. Each number and alphabet character has their own key. 379 | 380 | * ++1++ `++1++` for numbers 381 | * ++"l"++ `++"l"++` for lowercase character 382 | * ++u++ `++u++` for uppercase character or `++"U"++` for consistency 383 | 384 | [Punctionation keys](https://facelessuser.github.io/pymdown-extensions/extensions/keys/#punctuation-keys){target=_blank} use their name 385 | 386 | * ++spc++ `++spc++` 387 | * ++comma++ `++comma++` 388 | * ++arrow-left++ `++arrow-left++` 389 | 390 | For key sequences, place a space between each keyboard character 391 | 392 | * ++spc++ ++"g"++ ++"s"++ `++spc++ ++"g"++ ++"s"++` 393 | 394 | For key combinations, use join they key identifies with a `+` 395 | 396 | * ++meta+x++ `++meta+x++` 397 | * ++ctrl+alt+del++ `++ctrl+alt+del++` 398 | 399 | [MkDocs keyboard keys reference](https://facelessuser.github.io/pymdown-extensions/extensions/keys/#extendingmodifying-key-map-index){target=_blank .md-button} 400 | 401 | ## Images 402 | 403 | Markdown images can be appended with material tags to set the size of the image, whether to appear on light or dark theme and support lazy image loading in browsers 404 | 405 | === "Size" 406 | `{style="height:150px;width:150px"}` specifies the image size 407 | ```markdown 408 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){style="height:150px;width:150px"} 409 | ``` 410 | 411 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){style="height:150px;width:150px"} 412 | 413 | === "Lazy Loading" 414 | 415 | `{loading=lazy}` specifies an image should lazily load in the browser 416 | ```markdown 417 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png){loading=lazy} 418 | ``` 419 | 420 | === "Align" 421 | 422 | `{aligh=left}` or `{aligh=right}` specifies the page alignment of an image. 423 | ```markdown 424 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){align=right} 425 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){align=right} 426 | ``` 427 | 428 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png){align=left style="height:64px;width:64px"} 429 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png){align=right style="height:64px;width:64px"} 430 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 431 | 432 | === "Theme Specific" 433 | 434 | `![Kitty Logo](image/kitty-light.png#only-dark)` or `![Kitty Logo](image/kitty-light.png#only-light)` specifies the theme the image should be shown, allowing different versions of images to be shown based on the theme. 435 | ```markdown 436 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){style="height:150px;width:150px"} 437 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){style="height:150px;width:150px"} 438 | ``` 439 | Use the theme toggle in the top nav bar to see the icon change between light and dark. 440 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){style="height:150px;width:150px"} 441 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){style="height:150px;width:150px"} 442 | 443 | > Requires the [color pallet toggle](https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/#color-palette-toggle) 444 | 445 | === "All Image Attributes" 446 | Alight right, lazy load and set image to 150x150 447 | 448 | ```markdown 449 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){align=right loading=lazy style="height:64px;width:64px"} 450 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){align=right loading=lazy style="height:64px;width:64px"} 451 | ``` 452 | 453 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-light.png#only-dark){align=right loading=lazy style="height:64px;width:64px"} 454 | ![Kitty Logo](https://raw.githubusercontent.com/practicalli/graphic-design/live/icons/kitty-dark.png#only-light){align=left loading=lazy style="height:64px;width:64px"} 455 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 456 | 457 | ## Lists 458 | 459 | Task lists 460 | 461 | - [x] Lorem ipsum dolor sit amet, consectetur adipiscing elit 462 | - [ ] Vestibulum convallis sit amet nisi a tincidunt 463 | * [x] In hac habitasse platea dictumst 464 | * [x] In scelerisque nibh non dolor mollis congue sed et metus 465 | * [ ] Praesent sed risus massa 466 | - [ ] Aenean pretium efficitur erat, donec pharetra, ligula non scelerisque 467 | 468 | !!! EXAMPLE "Task List example" 469 | ```markdown 470 | - [x] Lorem ipsum dolor sit amet, consectetur adipiscing elit 471 | - [ ] Vestibulum convallis sit amet nisi a tincidunt 472 | * [x] In hac habitasse platea dictumst 473 | * [x] In scelerisque nibh non dolor mollis congue sed et metus 474 | * [ ] Praesent sed risus massa 475 | - [ ] Aenean pretium efficitur erat, donec pharetra, ligula non scelerisque 476 | ``` 477 | 478 | ## Tooltips 479 | 480 | The humble tool tip 481 | 482 | [Hover me](https://example.com "I'm a tooltip!") 483 | 484 | with references 485 | 486 | [Hover me][example] 487 | 488 | [example]: https://example.com "I'm a tooltip!" 489 | 490 | Icon tool tip with a title 491 | 492 | :material-information-outline:{ title="Important information" } 493 | 494 | ### Abreviations 495 | 496 | The HTML specification is maintained by the W3C. 497 | 498 | *[HTML]: Hyper Text Markup Language 499 | *[W3C]: World Wide Web Consortium 500 | 501 | ## Magic links 502 | 503 | [MagicLink](https://facelessuser.github.io/pymdown-extensions/extensions/magiclink/) can auto-link HTML, FTP, and email links. It can auto-convert repository links (GitHub, GitLab, and Bitbucket) and display them in a more concise, shorthand format. 504 | 505 | [Email Practicalli](mailto:info@) 506 | 507 | [Practicalli Neovim](https://github.com/practicalli/neovim) 508 | -------------------------------------------------------------------------------- /docs/version-control/index.md: -------------------------------------------------------------------------------- 1 | # Version Control 2 | 3 | 4 | ++spc++ ++"g"++ ++"s"++ to open Magit Status, providing a buffer to stage changes, create commits, add remotes, push changes. 5 | 6 | `@` Forge menu in Magit Status manages images and pull requests 7 | 8 | 9 | ## Setup Git Client 10 | 11 | 12 | ## Authenticated API access 13 | 14 | 15 | 16 | ## references 17 | 18 | * [Magit Forge configuration for Gitlab](https://gist.github.com/Azeirah/542f1db12e3ef904abfc7e9c2e83310e) 19 | -------------------------------------------------------------------------------- /docs/version-control/magit.md: -------------------------------------------------------------------------------- 1 | # Magit Git client 2 | 3 | ++spc++ ++"g"++ ++"s"++ to open magit status 4 | 5 | Magit Status buffer shows the status of the local and remote repository (when a remote is added) 6 | 7 | ++question++ to show the Magit Status help 8 | 9 | 10 | ## Navigating Magit Status buffer 11 | 12 | ++"j"++ / ++"k"++ to navigate line by line 13 | 14 | ++bracket-left++ / ++bracket-right++ to navigate by section, depending on the type of section the cursor is located (hunk, file, status) 15 | 16 | ++tab++ to toggle the expantion of the current sections. ++shift++ ++tab++ to toggle the expansion of all sections 17 | 18 | 19 | ## Stage Changes 20 | 21 | ++"s"++ to stage a file, hunk or visual selection, ++"S"++ to stage all unstaged changes. 22 | 23 | ++"u"++ to unstage a file, hunk or visual selection, ++"U"++ to unstage all staged changes. 24 | 25 | ++"v"++ ++"j"++ / ++"k"++ to select one or more lines within a hunk 26 | 27 | 28 | ## Stash changes 29 | 30 | ++"Z"++ to open the stash menu 31 | 32 | ??? WARNING "Evil key binding shadows Magit z stash menu" 33 | `z` in magit status buffer shows the Evil `z` menu rather than Magit stash menu, although there are some magit relevant commands in that menu. 34 | 35 | ++question++ to open magit-dispatch, showing the Magit top level menu. ++"z"++ now calls the Magit stash menu. Or use ++"Z"++ 36 | 37 | ++"Z"++ ++"z"++ to stash all the staged and unstaged changes, prompting for a meaningful name for the stash (to help remember what is inside the stash) 38 | 39 | ++"Z"++ ++"a"++ applies (copies) the contents of the stash into the working directory, adding back staged and unstaged changes. If the working copy has been modified since the stash, merge conflicts may occur and be highlighted in the magit status buffer. 40 | 41 | ++"Z"++ ++"a"++ as with apply but deletes the slash (unless there is a merge conflict and the stash is kept) 42 | 43 | ++"Z"++ ++"a"++ delected the current stash (under the cursor) 44 | 45 | 46 | ## Commits 47 | 48 | ++"c"++ opens the commit menu 49 | 50 | * ++"c"++ to create a new commit from the staged changes 51 | * ++"a"++ to amend an existing commit with the staged changes 52 | * ++"e"++ to extend a existing commit with the staged changes (skip editing the commit message) 53 | 54 | ++"c"++ opens the commit message buffer, using a commit message template if configured 55 | 56 | ++"a"++ opens the commit message buffer with the message from the current commit 57 | 58 | ++"Z"++ ++"Z"++ to create a new commit, including any changes maded to the commit message 59 | 60 | ++"Z"++ ++"Q"++ to abort the commit message 61 | 62 | ++enter++ on a commit, e.g. in recent commit section, opens the commit details that shows the commit message, meta data and the changes (diff) 63 | 64 | 65 | ## Changing History 66 | 67 | The latest commit can be ammended, extended, squashed from the ++c++ commit menu. 68 | 69 | ++"O"++ on a commit (in recent commits or log view) 70 | 71 | ++"r"++ rebase menu to change any part of the commit history 72 | 73 | 74 | ## Remote Repositories 75 | 76 | ++"M"++ opens the remote menu 77 | 78 | ++"a"++ to add a remote, specifying the name for the remote, e.g. `practicalli` 79 | 80 | ++"r"++ to rename an existing remote name, prompting to select the remote to rename 81 | 82 | ++"C"++ to configure an existing remote, i.e. to update the URL of the remote 83 | 84 | ++"P"++ opens the push menu, ++"p"++ to push all local changes to the remote repository (origin or what ever remote is set as the push default) 85 | 86 | ++"F"++ opens the pull menu, ++"p"++ to pull remote changes to the local repository, or ++"u"++ to pull from upstream, ++"e"++ to select the remote from those currently added. 87 | 88 | 89 | ## Merge Conflicts 90 | 91 | ++"e"++ on a conflicted file opens an ediff view, showing the original file on the left and the changes on the right, with a 3rd window at the bottom that contains the ediff commands. 92 | 93 | ++"j"++ / ++"k"++ to navigate by diff, moving the two main views in unison. 94 | 95 | ++"a"++ to retain the original text and update the change, or ++"b"++ to accept the new change into the original file 96 | 97 | > Pushing changes regularly minimises the risk of merge conflicts 98 | 99 | 100 | 101 | ## TODO list 102 | 103 | > TODO: is the magit-todo list included in doom or does it need to be added as a package? 104 | 105 | 106 | ## reference 107 | 108 | * [Magit key binding reference sheet](https://discourse.doomemacs.org/t/magit-keybind-reference-sheet/473) - Doom discourse 109 | -------------------------------------------------------------------------------- /includes/abbreviations.md: -------------------------------------------------------------------------------- 1 | *[HTML]: Hyper Text Markup Language 2 | *[W3C]: World Wide Web Consortium 3 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Practicalli Doom Emacs 3 | site_name: Practicalli Doom Emacs 4 | site_url: https://practical.li/doom-emacs 5 | site_description: Practical guide to Clojure development with Doom Emacs 6 | site_author: Practicalli 7 | site_org: https://practical.li/ 8 | copyright: Copyright © 2023 Practicali CC BY-SA 4.0 9 | repo_url: https://github.com/practicalli/doom-emacs/ 10 | edit_uri: https://github.com/practicalli/doom-emacs/edit/main/docs/ 11 | 12 | # Deployment 13 | # remote_name: origin 14 | remote_branch: gh-pages # deployment branch 15 | 16 | # Theme and styling 17 | theme: 18 | name: material 19 | logo: assets/images/practicalli-logo.png 20 | favicon: assets/favicon.svg 21 | features: 22 | - announce.dismiss 23 | - content.action.edit 24 | - content.action.view 25 | - content.code.annotate 26 | - content.code.copy 27 | - content.tabs.link 28 | - navigation.footer 29 | - navigation.indexes # Nav sections can have files 30 | - navigation.instant # Avoid page reloading for internal links 31 | - navigation.top 32 | - navigation.tracking # Update URL with anchor 33 | palette: 34 | # Palette toggle for light mode 35 | - media: "(prefers-color-scheme: light)" 36 | scheme: default 37 | primary: red 38 | accent: amber 39 | toggle: 40 | icon: material/brightness-7 41 | name: Switch to dark mode 42 | 43 | # Palette toggle for dark mode 44 | - media: "(prefers-color-scheme: dark)" 45 | scheme: slate 46 | primary: red 47 | accent: amber 48 | toggle: 49 | icon: material/brightness-4 50 | name: Switch to light mode 51 | # Override theme 52 | custom_dir: overrides 53 | 54 | extra_css: 55 | - assets/stylesheets/extra.css 56 | 57 | ## Additional styling 58 | markdown_extensions: 59 | - admonition 60 | - pymdownx.details 61 | - pymdownx.superfences 62 | - attr_list 63 | - md_in_html # Grids 64 | - footnotes # footnotes and abbreviations 65 | - pymdownx.emoji: 66 | emoji_index: !!python/name:material.extensions.emoji.twemoji 67 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 68 | - pymdownx.highlight: 69 | anchor_linenums: true 70 | - pymdownx.inlinehilite 71 | - pymdownx.snippets: 72 | url_download: true 73 | - pymdownx.superfences: 74 | custom_fences: 75 | - name: mermaid 76 | class: mermaid 77 | format: !!python/name:pymdownx.superfences.fence_code_format 78 | - pymdownx.tabbed: 79 | alternate_style: true 80 | - pymdownx.keys # keyboard keys 81 | - pymdownx.magiclink 82 | - def_list # lists 83 | - pymdownx.tasklist: 84 | custom_checkbox: true # checkboxes 85 | - toc: 86 | permalink: λ︎ 87 | 88 | ## Plugins 89 | plugins: 90 | # Explicitly add search plugin when defining plugins in this configuration file 91 | - search 92 | - callouts 93 | - glightbox # Image aligning 94 | - git-revision-date-localized: # Update and Creation date of each page 95 | # enable_creation_date: true 96 | fallback_to_build_date: true 97 | 98 | # Generate Social Cards via CI only 99 | # in assets/images/social 100 | - social: 101 | cards: !ENV [MKDOCS_SOCIAL_CARDS_GENERATE, true] 102 | 103 | # Redirect pages when moved or changed 104 | # - redirects: 105 | # redirect_maps: 106 | # changelog/insiders.md: insiders/changelog.md 107 | # reference/meta-tags.md: reference/index.md 108 | 109 | # Footer / Social Media 110 | extra: 111 | analytics: 112 | provider: google 113 | property: G-2YBWRFKXPS 114 | social: 115 | - icon: material/web 116 | link: https://practical.li/ 117 | - icon: fontawesome/brands/linkedin 118 | link: https://www.linkedin.com/in/jr0cket/ 119 | - icon: fontawesome/brands/slack 120 | link: https://clojurians.slack.com/messages/practicalli 121 | - icon: fontawesome/brands/twitter 122 | link: https://twitter.com/practical_li 123 | - icon: fontawesome/brands/github 124 | link: https://github.com/practicalli 125 | - icon: fontawesome/brands/docker 126 | link: https://hub.docker.com/u/practicalli 127 | 128 | # Navigation 129 | nav: 130 | - Overview: 131 | - index.md 132 | - REPL Workflow: introduction/repl-workflow.md 133 | - Why Doom Emacs: introduction/why-doom-emacs.md 134 | - Spacemacs To Doom: introduction/spacemacs-to-doom.md 135 | - Contributing: introduction/contributing.md 136 | - Writing Tips: introduction/writing-tips.md 137 | - Pre-install: install/pre-install.md 138 | - Install: 139 | - install/index.md 140 | - Doom Config: install/doom-configuration.md 141 | - Clojure: install/clojure-configuration.md 142 | - Bindings: install/bindings.md 143 | - Completion: install/completion.md 144 | # - Terminal: install/eshell.md 145 | # - Evil: install/evil-configuration.md 146 | # - Troubleshooting: install/troubleshooting.md 147 | - Doom Basics: 148 | - basics/index.md 149 | - Getting Help: basics/getting-help.md 150 | - Projects: basics/projects.md 151 | - Workspaces: basics/workspaces.md 152 | - Evil Editing: basics/evil-editing.md 153 | - Speaking Evil: basics/speaking-evil.md 154 | - Evil Reference: basics/vim-quick-reference.md 155 | - Evil Tools: basics/evil-tools.md 156 | - Snippets: basics/snippets.md 157 | - Clojure Workflow: 158 | - clojure-workflow/index.md 159 | - Version Control: 160 | - version-control/index.md 161 | - Magit Git Client: version-control/magit.md 162 | -------------------------------------------------------------------------------- /overrides/404.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | {% extends "main.html" %} 7 | 8 | 9 | {% block content %} 10 |

This is not the page you are looking for

11 | 12 |

13 | Sorry we have arrived at a page that does not exist... 14 |

15 | 16 |

17 | Practicalli Doom Emacs website is published using Material for MkDocs 18 |

19 | 20 |

21 | Try use the Search bar at the top of the page 22 |

23 | 24 | 31 | 32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /overrides/main.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | {% extends "base.html" %} 10 | 11 | 12 | {% block announce %} 13 | 14 | Practicalli Doom Emacs and its associated configuration are not actively maintained 15 | 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /overrides/partials/header.html: -------------------------------------------------------------------------------- 1 | 2 | {% set class = "md-header" %} {% if "navigation.tabs.sticky" in features %} {% 3 | set class = class ~ " md-header--shadow md-header--lifted" %} {% elif 4 | "navigation.tabs" not in features %} {% set class = class ~ " md-header--shadow" 5 | %} {% endif %} 6 | 7 | 8 |
9 | 74 | 75 | 76 | {% if "navigation.tabs.sticky" in features %} {% if "navigation.tabs" in 77 | features %} {% include "partials/tabs.html" %} {% endif %} {% endif %} 78 |
79 | -------------------------------------------------------------------------------- /overrides/partials/palette.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | {% for option in config.theme.palette %} 7 | {% set scheme = option.scheme | d("default", true) %} 8 | {% set primary = option.primary | d("indigo", true) %} 9 | {% set accent = option.accent | d("indigo", true) %} 10 | 25 | {% if option.toggle %} 26 | 34 | {% endif %} 35 | {% endfor %} 36 |
37 | -------------------------------------------------------------------------------- /overrides/partials/source.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | {% set icon = config.theme.icon.repo or "fontawesome/brands/git-alt" %} 4 | {% include ".icons/" ~ icon ~ ".svg" %} 5 |
6 |
7 | {{ config.repo_name }} 8 |
9 |
10 | --------------------------------------------------------------------------------