Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Folding issues #524

Open
jgollenz opened this issue Mar 10, 2023 · 14 comments
Open

Folding issues #524

jgollenz opened this issue Mar 10, 2023 · 14 comments
Labels
bug Something isn't working

Comments

@jgollenz
Copy link
Contributor

This is a meta-issue for bugs with folding

@jgollenz
Copy link
Contributor Author

jgollenz commented Mar 10, 2023

BUG: folding fails if the body of a headline was not inserted with o key.

How to reproduce:

  1. On a blank line, enter insert mode and type * foo.
  2. Without leaving insert mode, hit enter to go to a new line and type bar.
  3. Leave insert mode, go back to the heading and try to fold it with <TAB>.

This returns [orgmode] No fold. However, if you exit insert mode after inserting the heading and then hit o to enter the newline, folding will work.
This also seems to be influenced by our last line issue. Best to deal with that first.

@kristijanhusak
Copy link
Member

@jgollenz can you check if this is still happening? We switched to nvim-treesitter folding some time ago, so maybe this is fixed now.

@jgollenz
Copy link
Contributor Author

Nope, still happening for me

@gerazov

This comment was marked as resolved.

@kristijanhusak

This comment was marked as resolved.

@gerazov

This comment was marked as resolved.

@kristijanhusak

This comment was marked as resolved.

@gerazov

This comment was marked as resolved.

@ryan77627
Copy link

ryan77627 commented May 23, 2023

I may have a misconfiguration, as I'm new to this project, but I believe I am exhibiting the same behavior here but I do not know why.

For me to reproduce:

  1. Create a .org file
  2. Create a heading, then multiple subheadings (all in insert mode) with some desecriptions, like the example snippet.
  3. I get the "[orgmode] no folds" error. If I write the file, close the buffer, then reopen the file, it works fine.

I checked, my foldexpr is set to the proper nvim_treesitter#foldexpr(). Plus, it does work fine like described above if I create new lines using o and <leader>oih, but that requires a lot of switching between Normal and Insert mode.

Example org file:

#+title: Test file

* This is a header
** This is a subheader
   Some descriptive text
** This is another subheader
   More descriptive text

I have not messed around deep in configuration yet, so this is what my vim.init file looks like:

set nu rnu
imap kj <Esc>
set ts=4
set sw=4
set sts=4
set et
set mouse=

call plug#begin(stdpath('data') . '/plugged')
"Plug 'prabirshrestha/vim-lsp'
"Plug 'mattn/vim-lsp-settings'
"Plug 'prabirshrestha/asyncomplete.vim'
"Plug 'prabirshrestha/asyncomplete-lsp.vim'
"Plug 'Yggdroot/indentLine'
Plug 'nvim-treesitter/nvim-treesitter', {'do':':TSUpdate'}
Plug 'vim-pandoc/vim-pandoc'
Plug 'vim-pandoc/vim-pandoc-syntax'
Plug 'dhruvasagar/vim-table-mode'
Plug '~/.config/nvim/after'
Plug 'skywind3000/asyncrun.vim'
Plug 'folke/tokyonight.nvim', {'branch':'main'}
Plug 'nvim-lualine/lualine.nvim'
Plug 'nvim-tree/nvim-web-devicons'
Plug 'ms-jpq/coq_nvim', {'branch':'coq'}
Plug 'ms-jpq/coq.artifacts', {'branch':'artifacts'}
Plug 'nvim-orgmode/orgmode'
call plug#end()

"Load Theme
colorscheme tokyonight-night

"Load COQ Autocomplete
let g:coq_settings = {'auto_start':'shut-up'}

"Load LuaLine, COQ, and nvim-orgmode
lua << END
require('lualine').setup()
require('coq')
require('orgmode').setup_ts_grammar()
require('nvim-treesitter.configs').setup {
    highlight = {
        enable = true,
        additional_vim_regex_highlighting = {'org'},
    },
    ensure_installed = {'org', 'vim'},
}

require('orgmode').setup({
    org_agenda_files = {'~/Sync/org/**/*'},
    org_default_notes_file = '~/Sync/org/refile.org',
})

vim.opt.conceallevel = 2
vim.opt.concealcursor = nc

--local lspconfig = require('lspconfig')
END

"asynccomplete Auto Complete Config
"inoremap <expr> <Tab>   pumvisible() ? "\<C-n>" : "\<Tab>"
"inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
"inoremap <expr> <cr>    pumvisible() ? asyncomplete#close_popup() : "\<cr>"

"vim-table-mode config
let g:table_mode_corner_corner='+'
let g:table_mode_header_fillchar='='

"pandoc render and open preview
command Pv AsyncRun zathura '%:r.pdf'
command Rd silent exec "!pandoc -t pdf -o %:r.pdf --pdf-engine=xelatex --from=markdown+escaped_line_breaks -V geometry:margin=1in %"
command Rr exec "!pandoc -t pdf -o %:r.pdf --pdf-engine=xelatex --from=markdown+escaped_line_breaks -V geometry:margin=1in %"

"Auto-rerender markdown files to pdf
autocmd BufWritePost *.mkd :Rd

I should also mention the behavior is the same with nothing but the relevant treesitter and orgmode configurations within the LUA snippet present with no other plugins installed.

@ryan77627
Copy link

So quick update for me, folding works fine when the file is newly opened, and I found after some searching that zx updates the folds correctly and will work, it's just a matter of the folds not being auto updated when entering/leaving insert mode occasionally for whatever reason.

@lyz-code
Copy link

Whenever I run org_move_subtree_up or org_move_subtree_down on an item the moved item is hidden in the fold where it was going. So if it's moved down it's hidden inside the fold of the item below itself.

@lyz-code
Copy link

lyz-code commented Jan 26, 2024

The folding of the recurring tasks iterations is also kind of broken. For the next example

** TODO Recurring task
   DEADLINE: <2024-02-08 Thu .+14d -0d>
   :PROPERTIES:
   :LAST_REPEAT: [2024-01-25 Thu 11:53]
   :END:
   - State "DONE" from "TODO" [2024-01-25 Thu 11:53]
   - State "DONE" from "TODO" [2024-01-10 Wed 23:24]
   - State "DONE" from "TODO" [2024-01-03 Wed 19:39]
   - State "DONE" from "TODO" [2023-12-11 Mon 21:30]
   - State "DONE" from "TODO" [2023-11-24 Fri 13:10]
 
   - [ ] Do X

When folded the State changes is not added to the Properties fold. It's shown something like:

** TODO Recurring task
   DEADLINE: <2024-02-08 Thu .+14d -0d>
   :PROPERTIES:...                                                                                                                                                                                              
    
   - State "DONE" from "TODO" [2024-01-25 Thu 11:53]
   - State "DONE" from "TODO" [2024-01-10 Wed 23:24]
   - State "DONE" from "TODO" [2024-01-03 Wed 19:39]
   - State "DONE" from "TODO" [2023-12-11 Mon 21:30]
   - State "DONE" from "TODO" [2023-11-24 Fri 13:10]

   - [ ] Do X

I don't know if this is a bug or a feature, but when you have many iterations it's difficult to see the task description. So it would be awesome if they could be included into the properties fold or have their own fold.

EDIT: I've found that if you set the org_log_into_drawer = "LOGBOOK" in the config this is fixed.

lyz-code added a commit to lyz-code/blue-book that referenced this issue Feb 5, 2024
…Set host variables using a dynamic inventory

As with a normal inventory you can use the `host_vars` files with the proper name.

feat(sql#Get the schema of a table): Get the schema of a table

[Postgres](https://stackoverflow.com/questions/25639088/show-table-structure-and-list-of-tables-in-postgresql):

```
\d+ table_name
```

feat(coding_by_voice): Introduce Coding by voice
Coding by voice command requires two kinds of software: a [speech-recognition engine](speech_recognition.md) and a platform for voice coding. Dragon from Nuance, a speech-recognition software developer in Burlington, Massachusetts, is an advanced engine and is widely used for programming by voice. On the platform side, VoiceCode by Ben Meyer and Talon by Ryan Hileman (both are for Mac OS only) are popular.

Coding by voice platforms:

Two platforms for voice programming are Caster and Aenea, the latter of which runs on Linux. Both are free and open source, and enable voice-programming functionality in Dragonfly, which is an open-source Python framework that links actions with voice commands detected by a speech-recognition engine. Saphra tried Dragonfly, but found that setup required more use of her hands than she could tolerate.

All of these platforms for voice command work independently of coding language and text editor, and so can also be used for tasks outside programming. Pimentel, for instance, uses voice recognition to write e-mails, which he finds easier, faster and more natural than typing.

To the untrained ear, coding by voice command sounds like staccato bursts of a secret language. [Rudd’s video](https://www.youtube.com/watch?v=8SkdfdXWYaI) is full of terms like ‘slap’ (hit return), ‘sup’ (search up) and ‘mara’ (mark paragraph).

Unlike virtual personal assistants such as Apple’s Siri or Google’s Alexa, VoiceCode and Talon don’t do natural-language processing, so spoken instructions have to precisely match the commands that the system already knows. But both platforms use continuous command recognition, so users needn’t pause between commands, as Siri and Alexa require.

VoiceCode commands typically use words not in the English language, because if you use an English word as a command, such as ‘return’, it means you can never type out that word. By contrast, Talon, Aenea and Caster feature dynamic grammar, a tool that constantly updates which words the software can recognize on the basis of which applications are open. This means users can give English words as commands without causing confusion.

In addition to voice recognition, Talon can also replace a computer mouse with eye tracking, which requires a Tobii 4c eye tracker (US$150). Other eye-mousing systems generally require both the eye tracker and head-tracking hardware, such as the TrackIR from NaturalPoint. “I want to make fully hands-free use of every part of a desktop computer a thing,” says Hileman. Other mouse replacements also exist; Pimentel uses one called SmartNav.

Voice command requires at least a decent headset or microphone. Many users choose a unidirectional microphone so that others can talk to them while they are dictating code. One such mic, a cardioid mic, requires special equipment to supply power, and hardware costs can reach $400, says Pimentel.

The software can cost several hundred dollars too. The speech-recognition engine Dragon Professional costs $300, as does VoiceCode. Caster and Aenea are free and open source. Talon is available for free, but requires a separate speech-recognition engine. A beta version of Talon that includes a built-in speech-recognition engine is currently available to Hileman’s Patreon supporters for $15 per month. 

Whether or not users have RSI, it can be difficult and frustrating to start programming by voice. It took a month and a half for Pimentel to get up to speed, he says, and there were days when he was ready to throw in the towel. He printed out 40 pages of commands and forced himself to look at them until he learnt them. Saphra needed two months of coding, a little every day, before she felt that it was a “perfectly enjoyable experience and I could see myself doing this for a living”.

After the initial learning curve, users often create custom prompts for commonly used commands as the need arises. 

feat(yamllint#Ignore certain files): Ignore certain files

It is possible to exclude specific files or directories, so that the linter doesn’t process them. They can be provided either as a list of paths, or as a bulk string.

You can either totally ignore files (they won’t be looked at):

```yaml
extends: default

ignore: |
  /this/specific/file.yaml
  all/this/directory/
  *.template.yaml

ignore:
  - /this/specific/file.yaml
  - all/this/directory/
  - '*.template.yaml'
```

feat(efs): Troubleshoot don't have enough permissions to start restore from backup

That may be because the default EFS backup policy doesn't let you do that (stupid, I know).

To fix it go into the backup policy and remove the next line from the `Deny` policy:

```json
backup:StartRestoreJob
```

feat(habit_management#Select which habits you want to work with): Select which habits you want to work with

Our responses to the cues are so deeply encoded that it may feel like the urge to act comes from nowhere. For this reason, we must begin the process of behavior change with awareness. Before we can effectively build new habits, we need to get a handle on our current ones. The author suggests to do a list of your daily habits and rate them positively, negatively or neutral under the judgement of whether it brings you closer to the desired person you want to be.

I find this approach expensive time-wise if you already have a huge list of habits to work with. As it's my case I'll skip this part. You can read it in more detail in the chapter "4: The Man Who Didn't Look Right".

feat(habit_management#Working with the habit cues): Working with the habit cues

The first place to start the habit design is to understand and tweak the triggers that produce them. We'll do it by:

- [Clearly formulating the habits to change](habit_management.md#clearly-formulate-the-habit-you-want-to-change)
- [Stacking habits](habit_management.md#habit-stacking)
- [Using the environment to tweak your cues](habit_management.md#use-the-environment-to-tweak-your-cues)

feat(habit_management#Clearly formulate the habit you want to change): Clearly formulate the habit you want to change

The cues that can trigger an habit can come in a wide range of forms but the two most common are time and location. Being specific about what you want and how you will achieve it helps you say no to things that derail progress, distract your attention and pull you off course. And with enough repetition, you will get the urge to do the right thing at the right time, even if you can't say why. That's why it's interesting to formulate your habits as "I will [behaviour] at [time] in [location]".

You want the cue to be highly specific and immediately actionable. If there is room for doubt the implementation will suffer. Continuously refine the habit definitions as you catch the exceptions that drift you off.

If you aren't sure of when to start your habit, try the first day of the week, month or year. People are more likely to take action at those times because hope is usually higher as you get the feeling of a fresh start.

feat(habit_management#Habit stacking): Habit stacking

Many behaviours are linked together where the action of the first is the cue that triggers the next one. You can use this connection to build new habits based on your established ones. This may be called habit stacking. The formulation in this case is "After [current habit], I will [new habit]".

The key is to tie your desired behaviour into something you already do each day. Once you have mastered this basic structure, you can begin to create larger stacks by chaining small habits together. The catch is that the new habit should have the same frequency as the established one.

One way to find the right trigger for your habit stack is by brainstorming over:

- The list of your current habits.
- A new list of things that always happen to you with that frequency.

With these two lists, you can begin searching for the best triggers for the stack.

feat(habit_management#Use the environment to tweak your cues): Use the environment to tweak your cues

The cues that trigger a habit can start out very specific, but over time your habits become associated not with a single trigger but with the entire context surrounding the behaviour. This stacks over itself and your habits change depending on the room you are in and the cues in front of you. The context or the environment is then the invisible hand that shapes behaviours. They are not defined by the objects in the environment but by our relationship to them.

A new environment is a good foundation to make new habits, as you are free from the subtle triggers that nudge you toward your current habits. When you can't manage to get an entirely new environment, you can redefine or rearrange your current one.

When building good habits you can rearrange the environment to create obvious visual cues that draw your attention towards the desired habit. By sprinkling triggers throughout your surroundings, you increase the odds that you'll think about your habit throughout the day.

Once a habit has been encoded, the urge to act follows whenever the environmental cues reappear. This is why bad habits reinforce themselves. As you carry through the behaviour you spiral into a situation where the craving keeps growing and points you to keep on going with the same response. For example watching TV makes you feel sluggish, so you watch more television because you don't have the energy to do anything else.

Even if you manage to break a habit, you are unlikely to forget it's cues even if you don't do it for a while. That means that simply resisting temptation is an ineffective strategy. In the short run it may work. In the long run, as self-control is an exhausting task that consumes willpower, we become a product of the environment we live in. Trying to change a habit with self-control is doomed to fail as you may be able to resist temptation once or twice, but it's unlikely you can muster the willpower to override your desires every time. It's also very hard and frustrating to try to achieve change when you're under the mood influences of a bad habit.

A more reliable approach is to cut bad habits off at the source. Tweak the environment to make the cue virtually impossible to happen. That way you won't even have the chance to fall for the craving.

feat(habit_management#Temptation bundling): Temptation bundling

Dopamine is a neurotransmitter that can be used as the scientific measurement of craving. For years we assumed that it was all about pleasure, but now we know it plays a central role in many neurological processes, including motivation, learning and memory, punishment and aversion and voluntary movement.

Habits are a dopamine-driven feed back loop. It is released not only when you receive a reward but also when you anticipate it. This anticipation, and not the fulfillment of it, is what gets us to take action.

If we make a habit more attractive it will release more dopamine which will gives us more motivation to carry it through.

Temptation bundling works by pairing an action you want to do with an action you need to do. You're more likely to find a behaviour attractive if you get to do one of your favourite things at the same time. In the end you may even look forward to do the habit you need as it's related to the habit you want.

feat(habit_management#Align your personal identity change with an existent shared identity): Align your personal identity change with an existent shared identity

We pick up habits from the people around us. As a general rule, the closer we are to someone, the more likely we are to imitate some of their habits. One of the most effective things you can do to build better habits is to join a culture where your desired behaviour is the normal one. This transforms your personal identity transformation into the building of a shared one. Shared identities have great benefits over single ones:

- They foster belonging. A powerful feeling that creates motivation.
- They are more resilient: When one falters others will take their place so all together you'll guarantee the maintenance of the identity.
- They create friendship and community
- They expose you to an environment where more habits tied to that identity thrive.

Likewise, if you're trying to run from a bad habit cut your ties to communities that embrace that habit.

feat(immich): Introduce immich

Self-hosted photo and video backup solution directly from your mobile phone.

References:

- [Home](https://immich.app/)
- [Api](https://immich.app/docs/api)
- [Docs](https://immich.app/docs/overview/introduction)
- [Source](https://github.com/immich-app/immich).
- [Blog](https://immich.app/blog)
- [Demo](https://demo.immich.app/photos)

feat(immich#Installation): Installation

- Create a directory of your choice (e.g. `./immich-app`) to hold the `docker-compose.yml` and `.env` files.

  ```bash
  mkdir ./immich-app
  cd ./immich-app
  ```

- Download `docker-compose.yml`, `example.env` and optionally the `hwaccel.yml` files:

  ```bash
  wget -O docker-compose.yaml https://github.com/immich-app/immich/releases/latest/download/dockr-compose.yml
  wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
  wget https://github.com/immich-app/immich/releases/latest/download/hwaccel.yml
  ```
- Tweak those files with these thoughts in mind:
  - `immich` won't respect your upload media directory structure, so until you trust the softwar copy your media to the uploads directory.
  - immich is not stable so you need to disable the upgrade from watchtower. The easiest way is to [pin the latest stable version](https://github.com/immich-app/immich/pkgs/container/immich-server/versions?filters%5Bversion_type%5D=tagged) in the `.env` file.
  - Populate custom database information if necessary.
  - Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets.
  - Consider changing `DB_PASSWORD` to something randomly generated

- From the directory you created in Step 1, (which should now contain your customized `docker-compose.yml` and `.env` files) run:

  ```bash
  docker compose up -d
  ```

feat(immich#Configure smart search for other language): Configure smart search for other language

You can change to a multilingual model listed [here](https://huggingface.co/collections/immich-app/multilingual-clip-654eb08c2382f591eeb8c2a7) by going to Administration > Machine Learning Settings > Smart Search and replacing the name of the model.

Choose the one that has more downloads. For example, if you'd want the `
+immich-app/XLM-Roberta-Large-Vit-B-16Plus` model, you should only enter `XLM-Roberta-Large-Vit-B-16Plus` in the program configuration. Be careful not to add trailing whitespaces.

Be sure to re-run Smart Search on all assets after this change. You can then search in over 100 languages.

feat(immich#External storage): External storage

If you have an already existing library somewhere immich is installed you can use an [external library](https://immich.app/docs/guides/external-library). Immich will respect the files on that directory.

It won't create albums from the directory structure. If you want to do that check [this](https://github.com/alvistar/immich-albums) or [this](https://gist.github.com/REDVM/d8b3830b2802db881f5b59033cf35702) solutions.

feat(immich#My personal workflow): My personal workflow

I've tailored a personal workflow given the next thoughts:

- I don't want to expose Immich to the world, at least until it's a stable product.
- I already have in place a sync mechanism with [syncthing](syncthing.md) for all the mobile stuff
- I do want to still be able to share some albums with my friends and family.
- I want some mobile directories to be cleaned after importing the data (for example the `camera/DCIM`), but others should leave the files as they are after the import (OsmAnd+ notes).

Ingesting the files:

As all the files I want to ingest are sent to the server through syncthing, I've created a cron script that copies or moves the required files. Something like:

```bash

date
echo 'Updating the OsmAnd+ data'
rsync -auhvEX --progress /data/apps/syncthing/data/Osmand/avnotes /data/media/pictures/unclassified

echo 'Updating the Camera data'
mv /data/apps/syncthing/data/camera/Camera/* /data/media/pictures/unclassified/

echo 'Cleaning laptop home'
mv /data/media/downloads/*jpeg /data/media/downloads/*jpg /data/media/downloads/*png /data/media/pictures/unclassified/
echo
```

Where :

- `/data/media/pictures/unclassified` is a subpath of my [external library](#external-library).
- The last echo makes sure that the program exits with a return code of `0`. The script is improbable as it only takes into account the happy path, and I'll silently miss errors on it's execution. But as a first iteration it will do the job.

Then run the script in a cron and log the output to [`journald`](journald.md):

```cron
0 0 * * * /bin/bash /usr/local/bin/archive-photos.sh | /usr/bin/logger -t archive_fotos
```

Make sure to configure the update library cron job to run after this script has ended.

feat(immich#Not there yet): Not there yet

There are some features that are still lacking:

- [Image rotation](https://github.com/immich-app/immich/discussions/1695)
- [Smart albums](https://github.com/immich-app/immich/discussions/1673)
- [Image rating](https://github.com/immich-app/immich/discussions/3619)
- [Tags](https://github.com/immich-app/immich/discussions/1651)
- [Nested albums](https://github.com/immich-app/immich/discussions/2073#discussioncomment-6584926)
- [Duplication management](https://github.com/immich-app/immich/discussions/1968)
- [Search guide](https://github.com/immich-app/immich/discussions/3657)

feat(immich#Edit an image metadata): Edit an image metadata

You can't do it directly through the interface yet, use [exiftool](linux_snippets.md#Remove-image-metadata) instead.

This is interesting to remove the geolocation of the images that are not yours

feat(kitty): Suggest to use nerd fonts

If you're thinking of adding a new font, you should take a look at the [nerd fonts](https://www.nerdfonts.com/#home) as they patch developer targeted fonts with a high number of glyphs (icons). Specifically to add a high number of extra glyphs from popular ‘iconic fonts’ such as Font Awesome, Devicons, Octicons, and others.

For example you can get the [`FiraCode Nerd Font`](https://github.com/ryanoasis/nerd-fonts/releases/download/v3.1.1/FiraCode.zip)

feat(lazyvim): Introduce LazyVim

- [Source](https://github.com/LazyVim/LazyVim)
- [Docs](https://lazyvim.github.io/)
- [Home](https://lazyvim.github.io/)

feat(lazyvim#Adding plugins configuration): Adding plugins configuration

Configuring LazyVim plugins is exactly the same as using `lazy.nvim` to build a config from scratch.

For the full plugin spec documentation please check the [lazy.nvim readme](https://github.com/folke/lazy.nvim).

LazyVim comes with a list of preconfigured plugins, check them [here](https://www.lazyvim.org/configuration/plugins) before diving on your own.

feat(lazyvim#Adding a plugin): Adding a plugin

Adding a plugin is as simple as adding the plugin spec to one of the files under `lua/plugins/*.lua``. You can create as many files there as you want.

You can structure your `lua/plugins`` folder with a file per plugin, or a separate file containing all the plugin specs for some functionality. For example: `lua/plugins/lsp.lua`

```lua
return {
  -- add symbols-outline
  {
    "simrat39/symbols-outline.nvim",
    cmd = "SymbolsOutline",
    keys = { { "<leader>cs", "<cmd>SymbolsOutline<cr>", desc = "Symbols Outline" } },
    opts = {
      -- add your options that should be passed to the setup() function here
      position = "right",
    },
  },
}
```

Customizing plugin specs. Defaults merging rules:

- cmd: the list of commands will be extended with your custom commands
- event: the list of events will be extended with your custom events
- ft: the list of filetypes will be extended with your custom filetypes
- keys: the list of keymaps will be extended with your custom keymaps
- opts: your custom opts will be merged with the default opts
- dependencies: the list of dependencies will be extended with your custom dependencies
- any other property will override the defaults

For ft, event, keys, cmd and opts you can instead also specify a values function that can make changes to the default values, or return new values to be used instead.

```lua
-- change trouble config
{
  "folke/trouble.nvim",
  -- opts will be merged with the parent spec
  opts = { use_diagnostic_signs = true },
}

-- add cmp-emoji
{
  "hrsh7th/nvim-cmp",
  dependencies = { "hrsh7th/cmp-emoji" },
  ---@param opts cmp.ConfigSchema
  opts = function(_, opts)
    table.insert(opts.sources, { name = "emoji" })
  end,
}
```

Defining the plugin keymaps:

Adding `keys=` follows the rules as explained above. You don't have to specify a mode for `normal` mode keymaps.

You can also disable a default keymap by setting it to `false`. To override a keymap, simply add one with the same `lhs` and a new `rhs`. For example `lua/plugins/telescope.lua`

```lua
return {
  "nvim-telescope/telescope.nvim",
  keys = {
    -- disable the keymap to grep files
    {"<leader>/", false},
    -- change a keymap
    { "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Find Files" },
    -- add a keymap to browse plugin files
    {
      "<leader>fp",
      function() require("telescope.builtin").find_files({ cwd = require("lazy.core.config").options.root }) end,
      desc = "Find Plugin File",
    },
  },
},
```

Make sure to use the exact same mode as the keymap you want to disable.

```lua
return {
  "folke/flash.nvim",
  keys = {
    -- disable the default flash keymap
    { "s", mode = { "n", "x", "o" }, false },
  },
}
```
You can also return a whole new set of keymaps to be used instead. Or return `{}` to disable all keymaps for a plugin.

```lua
return {
  "nvim-telescope/telescope.nvim",
  -- replace all Telescope keymaps with only one mapping
  keys = function()
    return {
      { "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Find Files" },
    }
  end,
},
```

feat(lazyvim#Auto update plugins): Auto update plugins

Add this to `~/.config/nvim/lua/config/autocomds.lua`

```lua
local function augroup(name)
  return vim.api.nvim_create_augroup("lazyvim_" .. name, { clear = true })
end

vim.api.nvim_create_autocmd("VimEnter", {
  group = augroup("autoupdate"),
  callback = function()
    if require("lazy.status").has_updates then
      require("lazy").update({ show = false })
    end
  end,
})
```

feat(letsencrypt#Manually renew a certificate): Manually renew a certificate

Linuxserver swag container renews the certificates at night. If you don't have your server up at those hours your certificate won't be renewed automatically and you need to react to the prometheus alert manually. To do so get into the container and run `certbot renew`.

feat(life_planning):  Update the month planning

Decide the month objectives:

Create the month objectives in your roadmap file after addressing each element of:

- Your last month review document.
- The trimester objectives of your roadmap.

Once they are ready, copy them to the description of your `todo.org` file. That way you'll see it every day.

For each of your month objectives:

- Decide whether it makes sense to address it this month. If not, archive it
- Create a clear plan of action for this month on that objective
- Define the todo of each device (mobile, tablet, laptop)
- Tweak your *things to think about list*.
- Tweak your *reading list*.
- Tweak your week distribution (what to do in each day)
- If you selected maintenance week days tweak the priorities on your *maintenance list*.
- If you selected improvement week days tweak the priorities on your *improvements list*.
- Tweak your *habit manager system*.

feat(life_review): Use deadlines

Identify hard deadlines: Add a warning days before the deadline to make sure you're reminded until it's done.

feat(linux_snippets#Configure nginx to restrict methods): Configure nginx to restrict methods

```
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        if ($request_method !~ ^(GET|POST)$ ) {
            return 405;
        }

        try_files $uri $uri/ =404;
    }
}
```

feat(linux_snippets#Configure nginx location regexp to accept dashes): Configure nginx location regexp to accept dashes

```
location ~* /share/[\w-]+ {
  root /home/project_root;
}
```

feat(linux_snippets#Configure nginx location to accept many paths): Configure nginx location to accept many paths

```
location ~ ^/(static|media)/ {
  root /home/project_root;
}
```

feat(linux_snippets#Remove image metadata): Remove image metadata

```bash
exiftool -all:all= /path/to/file
```

feat(linux_snippets#Get the size increment of a directory between two dates): Get the size increment of a directory between two dates

To see how much has a directory grown between two dates you can use:

```bash
find /path/to/directory -type f -newerat 2022-12-31 ! -newerat 2024-01-01 -printf "%s\\n" | awk '{s+=$1} END {print s}'
```

It finds all the files in that directory that were created in the 2023, it only prints their size in bytes and then it adds them all up.

feat(loki#Prevent the too many outstanding requests error): Prevent the too many outstanding requests error

Add to your loki config the next options
```yaml

limits_config:
  split_queries_by_interval: 24h
  max_query_parallelism: 100

query_scheduler:
  max_outstanding_requests_per_tenant: 4096

frontend:
  max_outstanding_per_tenant: 4096
```

feat(vim_keymaps): Introduce vim keymaps

LazyVim comes with some sane default keybindings, you can see them [here](https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua). You don't need to remember them all, it also comes with [which-key](https://github.com/folke/which-key.nvim) to help you remember your keymaps. Just press any key like <space> and you'll see a popup with all possible keymaps starting with <space>.

- default `<leader>` is `<space>`
- default `<localleader>` is `\`

General editor bindings:

- Save file: `<C-s>`
- Quit all: `<leader>qq`
- Open a floating terminal: `<C-/>`

Movement keybindings:

- Split the windows:
  - Vertically: `<C-|`
  - Horizontally: `<C--`
- Delete window: `<leader>wd`
- To move around the windows you can use: <C-h>, <C-j>, <C-k>, <C-l>.
- To resize the windows use: <C-Up>, <C-Down>, <C-Left>, <C-Right>
- To move between buffers:
  - Next and previous with <S-h>, <S-l>
  - Switch to the previously opened buffer: `<leader>bb`

Coding keybindings:

Diagnostics:

- `<leader>cd>`: Shows you the diagnostics message of the current line in a floating window
- `]d` and `[d`: iterates over all diagnostics
- `]e` and `[e`: iterates over all error diagnostics
- `]w` and `[w`: iterates over all warning diagnostics

feat(vim_keymaps#Setting keymaps in lua): Setting keymaps in lua

If you need to set keymaps in lua you can use `vim.keymap.set`. For example:

```lua
vim.keymap.set('n', '<space>w', '<cmd>write<cr>', {desc = 'Save'})
```

After executing this, the sequence `Space + w` will call the `write` command. Basically, we can save changes made to a file with `Space + w`.

Let's dive into what does the  `vim.keymap.set` parameters mean.

```lua
vim.keymap.set({mode}, {lhs}, {rhs}, {opts})
```

* `{mode}`:  mode where the keybinding should execute. It can be a list of modes. We need to speify the mode's short name. Here are some of the most common.
  * `n`: Normal mode.
  * `i`: Insert mode.
  * `x`: Visual mode.
  * `s`: Selection mode.
  * `v`: Visual + Selection.
  * `t`: Terminal mode.
  * `o`: Operator-pending.
  * `''`: Yes, an empty string. Is the equivalent of `n + v + o`.

* `{lhs}`: is the key we want to bind.
* `{rhs}` is the action we want to execute. It can be a string with a command or an expression. You can also provide a lua function.
* `{opts}` this must be a lua table. If you don't know what is a "lua table" just think is a way of storing several values in one place. Anyway, it can have these properties.

  * `desc`: A string that describes what the keybinding does. You can write anything you want.
  * `remap`: A boolean that determines if our keybinding can be recursive. The default value is `false`. Recursive keybindings can cause some conflicts if used incorrectly. Don't enable it unless you know what you're doing.
  * `buffer`: It can be a boolean or a number. If we assign the boolean `true` it means the keybinding will only be effective in the current file. If we assign a number, it needs to be the "id" of an open buffer.
  * `silent`: A boolean. Determines whether or not the keybindings can show a message. The default value is `false`.
  * `expr`: A boolean. If enabled it gives the chance to use vimscript or lua to calculate the value of `{rhs}`. The default value is `false`.

feat(vim_keymaps#The leader key): The leader key

When creating keybindings we can use the special sequence `<leader>` in the `{lhs}` parameter, it'll take the value of the global variable `mapleader`.

So `mapleader` is a global variable in vimscript that can be string. For example.

```lua
vim.g.mapleader = ' '
```

After defining it we can use it as a prefix in our keybindings.

```lua
vim.keymap.set('n', '<leader>w', '<cmd>write<cr>')
```

This will make `<space key>` + `w` save the current file.

There are different opinions on what key to use as the `<leader>` key. The `<space>` is the most comfortable as it's always close to your thumbs, and it works well with both hands. Nevertheless, you can only use it in normal mode, because in insert `<space><whatever>` will be triggered as you write. An alternative is to use `;` which is also comfortable (if you use the english key distribution) and you can use it in insert mode.

If you [want to define more than one leader key](https://stackoverflow.com/questions/30467660/can-we-define-more-than-one-leader-key-in-vimrc) you can either:

* Change the `mapleader` many times in your file: As the value of `mapleader` is used at the moment the mapping is defined, you can indeed change that while plugins are loading. For that, you have to explicitly `:runtime` the plugins in your `~/.vimrc` (and count on the canonical include guard to prevent redefinition later):

  ```vim
  let mapleader = ','
  runtime! plugin/NERD_commenter.vim
  runtime! ...
  let mapleader = '\'
  runime! plugin/mark.vim
  ...
  ```
* Use the keys directly instead of using `<leader>`

  ```vim
  " editing mappings
  nnoremap ,a <something>
  nnoremap ,k <something else>
  nnoremap ,d <and something else>

  " window management mappings
  nnoremap gw <something>
  nnoremap gb <something else>
  ```

Defining `mapleader` and/or using `<leader>` may be useful if you change your mind often on what key to use a leader but it won't be of any use if your mappings are stable.

feat(neotree): Introduce neotree

General keymaps:

- `<cr>`: Open the file in the current buffer
- `<s>`: Open in a vertical split
- `<S>`: Open in an horizontal split
- `<bs>`: Navigate one directory up (even if it's the root of the `cwd`)

File and directory management:

- `a`: Create a new file or directory. Add a `/` to the end of the name to make a directory.
- `d`: Delete the selected file or directory
- `r`: Rename the selected file or directory
- `y`: Mark file to be copied (supports visual selection)
- `x`: Mark file to be cut (supports visual selection)
- `m`: Move the selected file or directory
- `c`: Copy the selected file or directory

References:

- [Docs](https://github.com/nvim-neo-tree/neo-tree.nvim/blob/main/doc/neo-tree.txt)
- [Wiki](https://github.com/nvim-neo-tree/neo-tree.nvim/wiki)
- [Wiki Recipes](https://github.com/nvim-neo-tree/neo-tree.nvim/wiki/Recipes)

feat(neotree#Show hidden files): Show hidden files

```lua
return {
  "nvim-neo-tree/neo-tree.nvim",
  opts = {
    filesystem = {
      filtered_items = {
        visible = true,
        show_hidden_count = true,
        hide_dotfiles = false,
        hide_gitignored = true,
        hide_by_name = {
          '.git',
        },
        never_show = {},
      },
    }
  }
}
```

feat(neotree#Autoclose on open file): Autoclose on open file

This example uses the file_open event to close the Neo-tree window when a file is opened. This applies to all windows and all sources at once.

```lua
require("neo-tree").setup({
  event_handlers = {

    {
      event = "file_opened",
      handler = function(file_path)
        -- auto close
        -- vimc.cmd("Neotree close")
        -- OR
        require("neo-tree.command").execute({ action = "close" })
      end
    },

  }
})
```

feat(neotree#Configuring vim folds): Configuring vim folds

Copy the code under [implementation](https://github.com/nvim-neo-tree/neo-tree.nvim/wiki/Recipes#emulating-vims-fold-commands) in your config file.

feat(neotree#Can't copy file/directory to itself): Can't copy file/directory to itself

If you want to copy a directory you need to assume that the prompt is done from within the directory. So if you want to copy it to a new name at the same level you need to use `../new-name` instead of `new-name`.

feat(orgmode#Using lazyvim): Install using lazyvim

```lua
return {
  'nvim-orgmode/orgmode',
  ```lua
    {
        'nvim-orgmode/orgmode',
        dependencies = {
      { 'nvim-treesitter/nvim-treesitter', lazy = true },
    },
        event = 'VeryLazy',
        config = function()
    -- Load treesitter grammar for org
    require('orgmode').setup_ts_grammar()

    -- Setup treesitter
    require('nvim-treesitter.configs').setup({
        highlight = {
          enable = true,
          additional_vim_regex_highlighting = { 'org' },
        },
        ensure_installed = { 'org' },
      })

    -- Setup orgmode
    require('orgmode').setup({
        org_agenda_files = '~/orgfiles/**/*',
        org_default_notes_file = '~/orgfiles/refile.org',
      })
  end,
  }
  ```
  dependencies = {
    { 'nvim-treesitter/nvim-treesitter', lazy = true },
  },
  event = 'VeryLazy',
  config = function()
    -- Load treesitter grammar for org
    require('orgmode').setup_ts_grammar()

    -- Setup treesitter
    require('nvim-treesitter.configs').setup({
      highlight = {
        enable = true,
        additional_vim_regex_highlighting = { 'org' },
      },
      ensure_installed = { 'org' },
    })

    -- Setup orgmode
    require('orgmode').setup({
      org_agenda_files = '~/orgfiles/**/*',
      org_default_notes_file = '~/orgfiles/refile.org',
    })
  end,
}
```

feat(orgmode#Troubleshoot orgmode with dap): Troubleshoot orgmode with dap

Use the next config and follow the steps of [Create an issue in the orgmode repository](orgmode.md#create-an-issue-in-the-orgmode-repository).

```lua
vim.cmd([[set runtimepath=$VIMRUNTIME]])
vim.cmd([[set packpath=/tmp/nvim/site]])

local package_root = '/tmp/nvim/site/pack'
local install_path = package_root .. '/packer/start/packer.nvim'

local function load_plugins()
  require('packer').startup({
    {
      'wbthomason/packer.nvim',
      { 'nvim-treesitter/nvim-treesitter' },
      { 'nvim-lua/plenary.nvim'},
      { 'nvim-orgmode/orgmode'},
      { 'nvim-telescope/telescope.nvim'},
      { 'lyz-code/telescope-orgmode.nvim' },
      { 'jbyuki/one-small-step-for-vimkind' },
      { 'mfussenegger/nvim-dap' },
      { 'kristijanhusak/orgmode.nvim', branch = 'master' },
    },
    config = {
      package_root = package_root,
      compile_path = install_path .. '/plugin/packer_compiled.lua',
    },
  })
end

_G.load_config = function()
  require('orgmode').setup_ts_grammar()
  require('nvim-treesitter.configs').setup({
    highlight = {
      enable = true,
      additional_vim_regex_highlighting = { 'org' },
    },
  })

  vim.cmd([[packadd nvim-treesitter]])
  vim.cmd([[runtime plugin/nvim-treesitter.lua]])
  vim.cmd([[TSUpdateSync org]])

  -- Close packer after install
  if vim.bo.filetype == 'packer' then
    vim.api.nvim_win_close(0, true)
  end

  require('orgmode').setup({
    org_agenda_files = {
      './*'
    }
  }
  )

  -- Reload current file if it's org file to reload tree-sitter
  if vim.bo.filetype == 'org' then
    vim.cmd([[edit!]])
  end
end
if vim.fn.isdirectory(install_path) == 0 then
  vim.fn.system({ 'git', 'clone', 'https://github.com/wbthomason/packer.nvim', install_path })
  load_plugins()
  require('packer').sync()
  vim.cmd([[autocmd User PackerCompileDone ++once lua load_config()]])
else
  load_plugins()
  load_config()
end

require('telescope').setup{
  defaults = {
    preview = {
     enable = true,
      treesitter = false,
    },
    vimgrep_arguments = {
      "ag",
      "--nocolor",
      "--noheading",
      "--numbers",
      "--column",
      "--smart-case",
      "--silent",
      "--follow",
      "--vimgrep",
    },
    file_ignore_patterns = {
      "%.svg",
      "%.spl",
      "%.sug",
      "%.bmp",
      "%.gpg",
      "%.pub",
      "%.kbx",
      "%.db",
      "%.jpg",
      "%.jpeg",
      "%.gif",
      "%.png",
      "%.org_archive",
      "%.flf",
      ".cache",
      ".git/",
      ".thunderbird",
      ".nas",
    },
    mappings = {
      i = {
        -- Required so that folding works when opening a file in telescope
        -- https://github.com/nvim-telescope/telescope.nvim/issues/559
        ["<CR>"] = function()
            vim.cmd [[:stopinsert]]
            vim.cmd [[call feedkeys("\<CR>")]]
        end,
        ['<C-j>'] = 'move_selection_next',
        ['<C-k>'] = 'move_selection_previous',
      }
    }
  },
  pickers = {
    find_files = {
      find_command = { "rg", "--files", "--hidden", "--glob", "!**/.git/*" },
      hidden = true,
      follow = true,
    }
  },
  extensions = {
    fzf = {
      fuzzy = true,                    -- false will only do exact matching
      override_generic_sorter = true,  -- override the generic sorter
      override_file_sorter = true,     -- override the file sorter
      case_mode = "smart_case",        -- or "ignore_case" or "respect_case"
                                       -- the default case_mode is "smart_case"
    },
    heading = {
      treesitter = true,
    },
  }
}

require('telescope').load_extension('orgmode')

local key = vim.keymap
vim.g.mapleader = ' '

local builtin = require('telescope.builtin')
key.set('n', '<leader>f', builtin.find_files, {})
key.set('n', '<leader>F', ':Telescope file_browser<cr>')

vim.api.nvim_create_autocmd('FileType', {
  pattern = 'org',
  group = vim.api.nvim_create_augroup('orgmode_telescope_nvim', { clear = true }),
  callback = function()
    vim.keymap.set('n', '<leader>r', require('telescope').extensions.orgmode.refile_heading)
    vim.keymap.set('n', '<leader>g', require('telescope').extensions.orgmode.search_headings)
  end,
})

require('orgmode').setup_ts_grammar()
local org = require('orgmode').setup({
  org_agenda_files = {
    "./*"
  },
  org_todo_keywords = { 'TODO(t)', 'CHECK(c)', 'DOING(d)', 'RDEACTIVATED(r)', 'WAITING(w)', '|','DONE(e)', 'REJECTED(j)', 'DUPLICATE(u)' },
  org_hide_leading_stars = true,
  org_deadline_warning_days = 0,
  win_split_mode = "horizontal",
  org_priority_highest = 'A',
  org_priority_default = 'C',
  org_priority_lowest = 'D',
  mappings = {
    global = {
      org_agenda = 'ga',
      org_capture = ';c',
    },
    org = {
      -- Enter new items
      org_meta_return = '<c-cr>',
      org_insert_heading_respect_content = ';<cr>',
      org_insert_todo_heading = "<c-t>",
      org_insert_todo_heading_respect_content = ";t",

      -- Heading promoting and demoting
      org_toggle_heading = '<leader>h',
      org_do_promote = '<h',
      org_do_demote = '>h',
      org_promote_subtree = '<H',
      org_demote_subtree = '>H',

      -- Heading moving
      org_move_subtree_up = "<leader>k",
      org_move_subtree_down = "<leader>j",

      -- Heading navigation
      org_next_visible_heading = '<c-j>',
      org_previous_visible_heading = '<c-k>',
      org_forward_heading_same_level = '<c-n>',
      org_backward_heading_same_level = '<c-p>',
      outline_up_heading = 'gp',
      org_open_at_point = 'gx',

      -- State transition
      org_todo = 't',

      -- Priority change
      org_priority_up = '-',
      org_priority_down = '=',

      -- Date management
      org_deadline = '<leader>d',
      org_schedule = '<leader>s',
      org_time_stamp = ';d',
      org_change_date = '<c-e>',

      -- Tag management
      org_set_tags_command = 'T',

      -- Archive management and refiling
      org_archive_subtree = ';a',
      org_toggle_archive_tag = ';A',
      -- org_refile = '<leader>r',  The refile is being handled below
    },
    agenda = {
      org_agenda_later = '<c-n>',
      org_agenda_earlier = '<c-p>',
      org_agenda_switch_to = '<tab>',
      org_agenda_goto = '<cr>',
      org_agenda_priority_up = '=',
      org_agenda_set_tags = 'T',
      org_agenda_deadline = '<leader>d',
      org_agenda_schedule = '<leader>s',
      org_agenda_archive = 'a',
    },
    capture = {
      org_capture_finalize = ';w',
      org_capture_refile = ';r',
      org_capture_kill = 'qqq',
    },
  }
})
local dap = require"dap"
dap.configurations.lua = {
  {
    type = 'nlua',
    request = 'attach',
    name = "Attach to running Neovim instance",
  }
}

dap.adapters.nlua = function(callback, config)
  callback({ type = 'server', host = config.host or "127.0.0.1", port = config.port or 8086 })
end

vim.api.nvim_set_keymap('n', '<leader>b', [[:lua require"dap".toggle_breakpoint()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>c', [[:lua require"dap".continue()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>n', [[:lua require"dap".step_over()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>m', [[:lua require"dap".repl.open()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>N', [[:lua require"dap".step_into()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<F12>', [[:lua require"dap.ui.widgets".hover()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<F5>', [[:lua require"osv".launch({port = 8086})<CR>]], { noremap = true })
```

feat(orgmode#Hide the state changes in the folds): Hide the state changes in the folds

The folding of the recurring tasks iterations is also kind of broken. For the next example

```orgmode
** TODO Recurring task
   DEADLINE: <2024-02-08 Thu .+14d -0d>
   :PROPERTIES:
   :LAST_REPEAT: [2024-01-25 Thu 11:53]
   :END:
   - State "DONE" from "TODO" [2024-01-25 Thu 11:53]
   - State "DONE" from "TODO" [2024-01-10 Wed 23:24]
   - State "DONE" from "TODO" [2024-01-03 Wed 19:39]
   - State "DONE" from "TODO" [2023-12-11 Mon 21:30]
   - State "DONE" from "TODO" [2023-11-24 Fri 13:10]

   - [ ] Do X
```

When folded the State changes is not added to the Properties fold. It's shown something like:

```orgmode
** TODO Recurring task
   DEADLINE: <2024-02-08 Thu .+14d -0d>
   :PROPERTIES:...
   - State "DONE" from "TODO" [2024-01-25 Thu 11:53]
   - State "DONE" from "TODO" [2024-01-10 Wed 23:24]
   - State "DONE" from "TODO" [2024-01-03 Wed 19:39]
   - State "DONE" from "TODO" [2023-12-11 Mon 21:30]
   - State "DONE" from "TODO" [2023-11-24 Fri 13:10]

   - [ ] Do X
```

I don't know if this is a bug or a feature, but when you have many iterations it's difficult to see the task description. So it would be awesome if they could be included into the properties fold or have their own fold.

I've found though that if you set the [`org_log_into_drawer = "LOGBOOK"` in the config](https://github.com/nvim-orgmode/orgmode/issues/455) this is fixed.

feat(orgmode#Things that are still broken or not developed): Things that are still broken or not developed

- [The agenda does not get automatically refreshed](https://github.com/nvim-orgmode/orgmode/issues/656)
- [Uncheck checkboxes on recurring tasks once they are completed](https://github.com/nvim-orgmode/orgmode/issues/655)
- [Foldings when moving items around](https://github.com/nvim-orgmode/orgmode/issues/524)
- [Refiling from the agenda](https://github.com/nvim-orgmode/orgmode/issues/657)
- [Interacting with the logbook](https://github.com/nvim-orgmode/orgmode/issues/149)

feat(photo_self_hosted): Do comparison of selfhosted photo software

There are [many alternatives to self host a photo management software](https://awesome-selfhosted.net/tags/photo-and-video-galleries.html), here goes my personal comparison. You should complement this article with [meichthys one](https://meichthys.github.io/foss_photo_libraries/).

!!! note "TL;DR: I'd first go with Immich, then LibrePhotos and then LycheeOrg"

| Software              | Home-Gallery    | Immich      | LibrePhotos |
| ---                   | ---             | ---         | ---         |
| UI                    | Fine            | Good        |  Fine       |
| Popular (stars)       | 614             | 25k         |  6k         |
| Active (PR/Issues)(1) | ?               | 251/231     |  27/16      |
| Easy deployment       | ?               | True        |  Complicated|
| Good docs             | True            | True        |  True       |
| Stable                | True            | False       |  True       |
| Smart search          | ?               | True        |  True       |
| Language | Javascript | Typescript | Python |
| Batch edit            | True            | True        |  ?          |
| Multi-user            | False           | True        |  ?          |
| Mobile app            | ?               | True        |  ?          |
| Oauth support         | ?               | True        |  ?          |
| Facial recognition    | ?               | True        |  ?          |
| Scales well           | False           | True        |  ?          |
| Favourites            | ?               | True        |  ?          |
| Archive               | ?               | True        |  ?          |
| Has API               | True            | True        |  ?          |
| Map support           | True            | True        |  ?          |
| Video Support         | True            | True        |  ?          |
| Discover similar      | True            | True        |  ?          |
| Static site           | True            | False       |  ?          |

- (1): It refers to the repository stats of the last month

**[Immich](immich.md)**:

References:

- [Home](https://immich.app/)
- [Demo](https://demo.immich.app/photos)
- [Source](https://github.com/immich-app/immich).

Pros:
- Smart search is awesome Oo
- create shared albums that people can use to upload and download
- map with leaflet
- explore by people and places
- docker compose
- optional [hardware acceleration](https://immich.app/docs/features/hardware-transcoding)
- very popular 25k stars, 1.1k forks
- has a [CLI](https://immich.app/docs/features/command-line-interface)
- can [load data from a directory](https://immich.app/docs/features/libraries)
- It has an [android app on fdroid to automatically upload media](https://immich.app/docs/features/mobile-app)
- [sharing libraries with other users](https://immich.app/docs/features/partner-sharing) and with the public
- favorites and archive
- public sharing
- oauth2, specially with [authentik <3](https://immich.app/docs/administration/oauth)
- extensive api: https://immich.app/docs/api/introduction
- It has an UI similar to google photos, so it would be easy for non technical users to use.
- Batch edit
- Discover similar through the smart search

Cons:

- If you want to get results outside the smart search you are going to have a bad time. There is still no way to filter the smart search results or even sort them. You're sold to the AI.
- dev suggests not to use watchtower as the project is in unstable alpha
- Doesn't work well in firefox
- It doesn't work with tags which you don't need because the smart search is so powerful.
- Scans pictures on the file system

**[LibrePhotos](https://docs.librephotos.com/)**:

References:

- [Source](https://github.com/LibrePhotos/librephotos)
- [Docs](https://docs.librephotos.com/docs/intro)
- [Demo](https://demo2.librephotos.com/login)
- [Outdated comparison](https://docs.librephotos.com/docs/user-guide/features)

Pros:

- [docker compose](https://docs.librephotos.com/docs/installation/standard-install), although you need to build the dockers yourself
- [android app](https://docs.librephotos.com/docs/user-guide/mobile/)
- 6k stars, 267 forks
- object, scene ai extraction

Cons:

- Not as good as Immich.

**[Home-Gallery](https://docs.home-gallery.org/general.html)**:

You can see the demo [here](https://demo.home-gallery.org/).

Nice features:

- Simple UI
- Discover similar images
- Static site generator
- Shift click to do batch editing

Cons:

- All users see all media
- The whole database is loaded into the browser and requires recent (mobile) devices and internet connection
- Current tested limits are about 400,000 images/videos

**Lycheeorg**:

References:

- [Home](https://lycheeorg.github.io/)
- [Docs](https://lycheeorg.github.io/docs)
- [Source](https://github.com/LycheeOrg/Lychee)

Pros:

- Sharing like it should be. One click and every photo and album is ready for the public. You can also protect albums with passwords if you want. It's under your control.
- Manual tags
- apparently safe upgrades
- docker compose
- 2.9k stars

Cons:
- demo doesn't show many features
- no ai

**Photoview**:

- [Home](https://photoview.github.io/)
- [Source](https://github.com/photoview/photoview)
- [Docs](https://photoview.github.io/en/docs/usage-people/)

Pros:

- Syncs with file system
- Albums and individual photos or videos can easily be shared by generating a public or password protected link.
- users support
- maps support
- 4.4k stars
- Face recognition

Cons:

- Demo difficult to understand as it's not in english
- mobile app only for ios
- last commit 6 months ago

**Pigallery2**:

References:

- [Home](https://bpatrik.github.io/pigallery2/)

Pros:

- map
- The gallery also supports *.gpx file to show your tracked path on the map too
- App supports full boolean logic with negation and exact or wildcard search. It also provides handy suggestions with autocomplete.
- face recognitiom: PiGallery2 can read face reagions from photo metadata. Current limitation: No ML-based, automatic face detection.
- rating and grouping by rating
- easy query builder
- video transcoding
- blog support. Markdown based blogging support

  You can write some note in the *.md files for every directory

- You can create logical albums (a.k.a.: Saved search) from any search query. Current limitation: It is not possible to create albums from a manually picked photos.
- PiGallery2 has a rich settings page where you can easily set up the gallery.

Cons:
- no ml face recognition

**Piwigo**:

References:

- [Home](piwigo.org)
- [Source](https://github.com/Piwigo/Piwigo)

Piwigo is open source photo management software. Manage, organize and share your photo easily on the web. Designed for organisations, teams and individuals

Pros:

- Thousands of organizations and millions of individuals love using Piwigo
- shines when it comes to classifying thousands or even hundreds of thousands of photos.
- Born in 2002, Piwigo has been supporting its users for more than 21 years. Always evolving!
- You can add photos with the web form, any FTP client ora desktop application like digiKam, Shotwell, Lightroom ormobile applications.
- Filter photos from your collection, make a selection and apply actions in batch: change the author, add some tags, associate to a new album, set geolocation...
- Make your photos private and decide who can see each of them. You can set permissions on albums and photos, for groups or individual users.
- Piwigo can read GPS latitude and longitude from embedded metadata. Then, with plugin for Google Maps or OpenStreetMap, Piwigo can display your photos on an interactive map.
- Change appearance with themes. Add features with plugins. Extensions require just a few clicks to get installed. 350 extensions available, and growing!
- With the Fotorama plugin, or specific themes such as Bootstrap Darkroom, you can experience the full screen slideshow.
- Your visitors can post comments, give ratings, mark photos as favorite, perform searches and get notified of news by email.
- Piwigo web API makes it easy for developers to perform actions from other applications
- GNU General Public License, or GPL
- 2.9 k stars, 400 forks
- still active
- nice release documents: https://piwigo.org/release-14.0.0

Cons:

- Official docs don't mention docker
- no demo: https://piwigo.org/demo
- Unpleasant docs: https://piwigo.org/doc/doku.php
- Awful plugin search: https://piwigo.org/ext/

**[Damselfly](https://damselfly.info/)**:

Fast server-based photo management system for large collections of images. Includes face detection, face & object recognition, powerful search, and EXIF Keyword tagging. Runs on Linux, MacOS and Windows.

Very ugly UI

**[Saigal](https://github.com/saimn/sigal)**:

Too simple

**[Spis](https://github.com/gbbirkisson/spis)**:

Low number of maintainers
Too simple

feat(promtail#Pipeline building): Pipeline building

In [this issue](https://github.com/grafana/loki/issues/6165) there are nice examples on different pipelines.

feat(promtail#Drop logs): Drop logs

If you don't want the logs that have the keyword `systemd-journal` and value `docker-compose` you can add the next pipeline stage:

```yaml
pipeline_stages:
  - drop:
      source: syslog_identifier
      value: docker-compose
```

feat(rich): Adding a footer to a table

Adding a footer is not easy task. [This answer](https://github.com/Textualize/rich/discussions/2135) doesn't work anymore as `table` doesn't have the `add_footer`. You need to create the footer in the `add_column` so you need to have the data that needs to go to the footer before building the rows.

You would do something like:

```python
table = Table(title="Star Wars Movies", show_footer=True)
table.add_column("Title", style="magenta", footer='2342')
```

feat(route_management): Introduce route management

To analyze which hiking routes are available in a zone I'm following the next process

- [ ] Check in my `trips` orgmode directory to see if the zone has already been indexed.
- [ ] Do a first search of routes
  - [ ] Identify which books or magazines describe the zone
  - [ ] For each of the described routes in each of these books:
    - [ ] Create the `Routes` section with tag `:route:` if it doesn't exist
    - [ ] Fill up the route form in a `TODO` heading. Something similar to:
      ~~~
      Reference: Book Page
      Source: Where does it start
      Distance: X km
      Slope: X m
      Type: [Lineal/Circular/Semi-lineal]
      Difficulty:
      Track: URL (only if you don't have to search for it)
      ~~~
    - [ ] Add tags of the people I'd like to do it with
    - [ ] Put a postit on the book/magazine if it's likely I'm going to do it
    - [ ] Open a web maps tab with the source of the route to calculate the time from the different lodgins
  - [ ] If there are not enough, repeat the process above for each of your online route reference blogs

- [ ] Choose the routes to do
  - [ ] Show the gathered routes to the people you want to go with
  - [ ] Select which ones you'll be more likely to do

- [ ] For each of the chosen routes
  - [ ] Search the track in wikiloc if it's missing
  - [ ] Import the track in [OsmAnd+](osmand.md)

feat(vim_config): Configure vim from scratch

Neovim configuration is a **complex** thing to do, both to start and to maintain. The configurations are endless, the plugins are too. Be ready to spend a lot of energy on it and to get lost reading a lot.

If I'm scaring you, you are right to be scared! xD. Once you manage to get it configured to your liking you'll think that in the end it doesn't even matter spending all that time. However if you're searching for something that is plug and play try [vscodium](vscodium.md).

To make things worse, the configuration [is done in lua](#configuration-done-in-Lua), so you may need  a [small refreshment](lua.md) to understand what are you doing.

feat(vim_config#Vim distributions): Vim distributions

One way to make vim's configuration more bearable is to use vim distributions. These are projects that maintain configurations with sane defaults and that work with the whole ecosystem of plugins.

Using them is the best way to:

- Have something usable fast
- Minimize the maintenance efforts as others are doing it for you (plugin changes, breaking changes, ..)
- Keep updated with the neovim ecosystem, as you can see what is the community adding to the default config.

However, there are so many good Neovim configuration distributions that it becomes difficult for a Neovim user to decide which distribution to use and how to tailor it for their use case.

By far, the top 5 Neovim configuration distributions are [AstroNvim](https://github.com/AstroNvim/AstroNvim), [kickstart](https://github.com/nvim-lua/kickstart.nvim), [LazyVim](https://github.com/LazyVim/LazyVim), [LunarVim](https://github.com/LunarVim/LunarVim), and [NvChad](https://github.com/NvChad/NvChad). That is not to say these are the “best” configuration distributions, simply that they are the most popular.

Each of these configuration distributions has value. They all provide excellent starting points for crafting your own custom configuration, they are all extensible and fairly easy to learn, and they all provide an out-of-the-box setup that can be used effectively without modification.

Distinguishing features of the top Neovim configuration distributions are:

- AstroNvim:

    - An excellent community repository
    - Fully featured out-of-the-box
    - Good documentation

- kickstart

    - Minimal out-of-the-box setup
    - Easy to extend and widely used as a starting point
    - A good choice if your goal is hand-crafting your own config

- LazyVim

    - Very well maintained by the author of lazy.nvim
    - Nice architecture, it’s a plugin with which you can import preconfigured plugins
    - Good documentation

- LunarVim

    - Well maintained and mature
    - Custom installation processs installs LunarVim in an isolated location
    - Been around a while, large community, widespread presence on the web

- NvChad

    - Really great base46 plugin enables easy theme/colorscheme management
    - Includes an impressive mappings cheatsheet
    - ui plugin and nvim-colorizer

Personally I tried LunarVim and finally ended up with LazyVim because:

- It's more popular
- I like the file structure
- It's being maintained by [folke](https://github.com/folke) one of the best developers of neovim plugins.

feat(vim_config#Starting your configuration with LazyVim): Starting your configuration with LazyVim

[Installing the requirements](https://www.lazyvim.org/):

LazyVim needs the next tools to be able to work:

- Neovim >= 0.9.0 (needs to be built with LuaJIT). Follow [these instructions](vim.md#installation)
- Git >= 2.19.0 (for partial clones support). `sudo apt-get install git`.
- a [Nerd Font(v3.0 or greater)](https://www.nerdfonts.com/) (optional, but strongly suggested as they rae needed to display some icons). Follow [these instructions if you're using kitty](kitty.md#fonts).
- lazygit (optional and I didn't like it)
- a C compiler for nvim-treesitter. `apt-get install gcc`
- for telescope.nvim (optional)
  - live grep: `ripgrep`
  - find files: `fd`
- a terminal that support true color and undercurl:
  - [kitty (Linux & Macos)](kitty.md)
  - wezterm (Linux, Macos & Windows)
  - alacritty (Linux, Macos & Windows)
  - iterm2 (Macos)

[Install the starter](https://www.lazyvim.org/installation):

- Make a backup of your current Neovim files:
    ```bash
    # required
    mv ~/.config/nvim{,.old}

    # optional but recommended
    mv ~/.local/share/nvim{,.old}
    mv ~/.local/state/nvim{,.old}
    mv ~/.cache/nvim{,.old}
    ```
- Clone the starter

    ```bash
    git clone https://github.com/LazyVim/starter ~/.config/nvim
    ```

- Remove the `.git` folder, so you can add it to your own repo later

    ```bash
    rm -rf ~/.config/nvim/.git
    ```

- Start Neovim!

    ```bash
    nvim
    ```
- It is recommended to run `:LazyHealth` after installation. This will load all plugins and check if everything is working correctly.

[Understanding the file structure](https://www.lazyvim.org/configuration):

The files under `config` will be automatically loaded at the appropriate time, so you don't need to require those files manually.

You can add your custom plugin specs under `lua/plugins/`. All files there will be automatically loaded by lazy.nvim.

```
~/.config/nvim
├── lua
│   ├── config
│   │   ├── autocmds.lua
│   │   ├── keymaps.lua
│   │   ├── lazy.lua
│   │   └── options.lua
│   └── plugins
│       ├── spec1.lua
│       ├── **
│       └── spec2.lua
└── init.toml
```
The files `autocmds.lua`, `keymaps.lua`, `lazy.lua` and `options.lua` under `lua/config` will be automatically loaded at the appropriate time, so you don't need to require those files manually. LazyVim comes with a set of default config files that will be loaded before your own.

You can continue your config by [adding plugins](lazyvim.md).

feat(vim_dap): Introduce Debug Adapter Protocol

`nvim-dap`](https://github.com/mfussenegger/nvim-dap) implements a client for the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/overview). This allows a client to control a debugger over a documented API. That allows us to control the debugger from inside neovim, being able to set breakpoints, evaluate runtime values of variables, and much more.

`nvim-dap` is not configured for any language by default. You will need to set up a configuration for each language. For the configurations you will need adapters to run.

I would suggest starting with 2 actions. Setting breakpoints and “running” the debugger. The debugger allows us to stop execution and look at the current state of the program. Setting breakpoints will allow us to stop execution and see what the current state is.

```lua
vim.api.nvim_set_keymap('n', '<leader>b', [[:lua require"dap".toggle_breakpoint()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>c', [[:lua require"dap".continue()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>n', [[:lua require"dap".step_over()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>N', [[:lua require"dap".step_into()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<F5>', [[:lua require"osv".launch({port = 8086})<CR>]], { noremap = true })
```

Go to a line where a conditional or value is set and toggle a breakpoint. Then, we’ll start the debugger. If done correctly, you’ll see an arrow next to your line of code you set a breakpoint at.

There is no UI with dap by default. You have a few options for UI [nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)

In the `dap` repl you can [use the next operations](https://github.com/mfussenegger/nvim-dap/blob/master/doc/dap.txt):

- `.exit`: Closes the REPL
- `.c` or `.continue`: Same as |`dap.continue`|
- `.n` or `.next`: Same as |`dap.step_over`|
- `.into`: Same as |`dap.step_into`|
- `.into_target`: Same as |`dap.step_into{askForTargets=true}`|
- `.out`: Same as |`dap.step_out`|
- `.up`: Same as |`dap.up`|
- `.down`: Same as |`dap.down`|
- `.goto`: Same as |`dap.goto_`|
- `.scopes`: Prints the variables in the current s`cope`s
- `.threads`: Prints all t`hread`s
- `.frames`: Print the stack f`rame`s
- `.capabilities`: Print the capabilities of the debug a`dapte`r
- `.b` or `.back`: Same as |`dap.step_back`|
- `.rc` or `.reverse-continue`: Same as |`dap.reverse_continue`|

feat(vim_dap#nvim-dap-ui): Introduce nvim-dap-ui

Install with packer:

```lua
use { "rcarriga/nvim-dap-ui", requires = {"mfussenegger/nvim-dap"} }
```

It is highly recommended to use [`neodev.nvim`](https://github.com/folke/neodev.nvim) to enable type checking for `nvim-dap-ui` to get type checking, documentation and autocompletion for all API functions.

```lua
require("neodev").setup({
  library = { plugins = { "nvim-dap-ui" }, types = true },
  ...
})
```
`nvim-dap-ui` is built on the idea of "elements". These elements are windows which provide different features.

Elements are grouped into layouts which can be placed on any side of the screen. There can be any number of layouts, containing whichever elements desired.

Elements can also be displayed temporarily in a floating window.

Each element has a set of mappings for element-specific possible actions, detailed below for each element. The total set of actions/mappings and their default shortcuts are:

- edit: `e`
- expand: `<CR>` or left click
- open: `o`
- remove: `d`
- repl: `r`
- toggle: `t`

See `:h dapui.setup()` for configuration opti…
lyz-code added a commit to lyz-code/blue-book that referenced this issue Feb 6, 2024
…Set host variables using a dynamic inventory

As with a normal inventory you can use the `host_vars` files with the proper name.

feat(sql#Get the schema of a table): Get the schema of a table

[Postgres](https://stackoverflow.com/questions/25639088/show-table-structure-and-list-of-tables-in-postgresql):

```
\d+ table_name
```

feat(coding_by_voice): Introduce Coding by voice

Coding by voice command requires two kinds of software: a [speech-recognition engine](speech_recognition.md) and a platform for voice coding. Dragon from Nuance, a speech-recognition software developer in Burlington, Massachusetts, is an advanced engine and is widely used for programming by voice. On the platform side, VoiceCode by Ben Meyer and Talon by Ryan Hileman (both are for Mac OS only) are popular.

Coding by voice platforms:

Two platforms for voice programming are Caster and Aenea, the latter of which runs on Linux. Both are free and open source, and enable voice-programming functionality in Dragonfly, which is an open-source Python framework that links actions with voice commands detected by a speech-recognition engine. Saphra tried Dragonfly, but found that setup required more use of her hands than she could tolerate.

All of these platforms for voice command work independently of coding language and text editor, and so can also be used for tasks outside programming. Pimentel, for instance, uses voice recognition to write e-mails, which he finds easier, faster and more natural than typing.

To the untrained ear, coding by voice command sounds like staccato bursts of a secret language. [Rudd’s video](https://www.youtube.com/watch?v=8SkdfdXWYaI) is full of terms like ‘slap’ (hit return), ‘sup’ (search up) and ‘mara’ (mark paragraph).

Unlike virtual personal assistants such as Apple’s Siri or Google’s Alexa, VoiceCode and Talon don’t do natural-language processing, so spoken instructions have to precisely match the commands that the system already knows. But both platforms use continuous command recognition, so users needn’t pause between commands, as Siri and Alexa require.

VoiceCode commands typically use words not in the English language, because if you use an English word as a command, such as ‘return’, it means you can never type out that word. By contrast, Talon, Aenea and Caster feature dynamic grammar, a tool that constantly updates which words the software can recognize on the basis of which applications are open. This means users can give English words as commands without causing confusion.

In addition to voice recognition, Talon can also replace a computer mouse with eye tracking, which requires a Tobii 4c eye tracker (US$150). Other eye-mousing systems generally require both the eye tracker and head-tracking hardware, such as the TrackIR from NaturalPoint. “I want to make fully hands-free use of every part of a desktop computer a thing,” says Hileman. Other mouse replacements also exist; Pimentel uses one called SmartNav.

Voice command requires at least a decent headset or microphone. Many users choose a unidirectional microphone so that others can talk to them while they are dictating code. One such mic, a cardioid mic, requires special equipment to supply power, and hardware costs can reach $400, says Pimentel.

The software can cost several hundred dollars too. The speech-recognition engine Dragon Professional costs $300, as does VoiceCode. Caster and Aenea are free and open source. Talon is available for free, but requires a separate speech-recognition engine. A beta version of Talon that includes a built-in speech-recognition engine is currently available to Hileman’s Patreon supporters for $15 per month. 

Whether or not users have RSI, it can be difficult and frustrating to start programming by voice. It took a month and a half for Pimentel to get up to speed, he says, and there were days when he was ready to throw in the towel. He printed out 40 pages of commands and forced himself to look at them until he learnt them. Saphra needed two months of coding, a little every day, before she felt that it was a “perfectly enjoyable experience and I could see myself doing this for a living”.

After the initial learning curve, users often create custom prompts for commonly used commands as the need arises. 

feat(yamllint#Ignore certain files): Ignore certain files

It is possible to exclude specific files or directories, so that the linter doesn’t process them. They can be provided either as a list of paths, or as a bulk string.

You can either totally ignore files (they won’t be looked at):

```yaml
extends: default

ignore: |
  /this/specific/file.yaml
  all/this/directory/
  *.template.yaml

ignore:
  - /this/specific/file.yaml
  - all/this/directory/
  - '*.template.yaml'
```

feat(efs): Troubleshoot don't have enough permissions to start restore from backup

That may be because the default EFS backup policy doesn't let you do that (stupid, I know).

To fix it go into the backup policy and remove the next line from the `Deny` policy:

```json
backup:StartRestoreJob
```

feat(habit_management#Select which habits you want to work with): Select which habits you want to work with

Our responses to the cues are so deeply encoded that it may feel like the urge to act comes from nowhere. For this reason, we must begin the process of behavior change with awareness. Before we can effectively build new habits, we need to get a handle on our current ones. The author suggests to do a list of your daily habits and rate them positively, negatively or neutral under the judgement of whether it brings you closer to the desired person you want to be.

I find this approach expensive time-wise if you already have a huge list of habits to work with. As it's my case I'll skip this part. You can read it in more detail in the chapter "4: The Man Who Didn't Look Right".

feat(habit_management#Working with the habit cues): Working with the habit cues

The first place to start the habit design is to understand and tweak the triggers that produce them. We'll do it by:

- [Clearly formulating the habits to change](habit_management.md#clearly-formulate-the-habit-you-want-to-change)
- [Stacking habits](habit_management.md#habit-stacking)
- [Using the environment to tweak your cues](habit_management.md#use-the-environment-to-tweak-your-cues)

feat(habit_management#Clearly formulate the habit you want to change): Clearly formulate the habit you want to change

The cues that can trigger an habit can come in a wide range of forms but the two most common are time and location. Being specific about what you want and how you will achieve it helps you say no to things that derail progress, distract your attention and pull you off course. And with enough repetition, you will get the urge to do the right thing at the right time, even if you can't say why. That's why it's interesting to formulate your habits as "I will [behaviour] at [time] in [location]".

You want the cue to be highly specific and immediately actionable. If there is room for doubt the implementation will suffer. Continuously refine the habit definitions as you catch the exceptions that drift you off.

If you aren't sure of when to start your habit, try the first day of the week, month or year. People are more likely to take action at those times because hope is usually higher as you get the feeling of a fresh start.

feat(habit_management#Habit stacking): Habit stacking

Many behaviours are linked together where the action of the first is the cue that triggers the next one. You can use this connection to build new habits based on your established ones. This may be called habit stacking. The formulation in this case is "After [current habit], I will [new habit]".

The key is to tie your desired behaviour into something you already do each day. Once you have mastered this basic structure, you can begin to create larger stacks by chaining small habits together. The catch is that the new habit should have the same frequency as the established one.

One way to find the right trigger for your habit stack is by brainstorming over:

- The list of your current habits.
- A new list of things that always happen to you with that frequency.

With these two lists, you can begin searching for the best triggers for the stack.

feat(habit_management#Use the environment to tweak your cues): Use the environment to tweak your cues

The cues that trigger a habit can start out very specific, but over time your habits become associated not with a single trigger but with the entire context surrounding the behaviour. This stacks over itself and your habits change depending on the room you are in and the cues in front of you. The context or the environment is then the invisible hand that shapes behaviours. They are not defined by the objects in the environment but by our relationship to them.

A new environment is a good foundation to make new habits, as you are free from the subtle triggers that nudge you toward your current habits. When you can't manage to get an entirely new environment, you can redefine or rearrange your current one.

When building good habits you can rearrange the environment to create obvious visual cues that draw your attention towards the desired habit. By sprinkling triggers throughout your surroundings, you increase the odds that you'll think about your habit throughout the day.

Once a habit has been encoded, the urge to act follows whenever the environmental cues reappear. This is why bad habits reinforce themselves. As you carry through the behaviour you spiral into a situation where the craving keeps growing and points you to keep on going with the same response. For example watching TV makes you feel sluggish, so you watch more television because you don't have the energy to do anything else.

Even if you manage to break a habit, you are unlikely to forget it's cues even if you don't do it for a while. That means that simply resisting temptation is an ineffective strategy. In the short run it may work. In the long run, as self-control is an exhausting task that consumes willpower, we become a product of the environment we live in. Trying to change a habit with self-control is doomed to fail as you may be able to resist temptation once or twice, but it's unlikely you can muster the willpower to override your desires every time. It's also very hard and frustrating to try to achieve change when you're under the mood influences of a bad habit.

A more reliable approach is to cut bad habits off at the source. Tweak the environment to make the cue virtually impossible to happen. That way you won't even have the chance to fall for the craving.

feat(habit_management#Temptation bundling): Temptation bundling

Dopamine is a neurotransmitter that can be used as the scientific measurement of craving. For years we assumed that it was all about pleasure, but now we know it plays a central role in many neurological processes, including motivation, learning and memory, punishment and aversion and voluntary movement.

Habits are a dopamine-driven feed back loop. It is released not only when you receive a reward but also when you anticipate it. This anticipation, and not the fulfillment of it, is what gets us to take action.

If we make a habit more attractive it will release more dopamine which will gives us more motivation to carry it through.

Temptation bundling works by pairing an action you want to do with an action you need to do. You're more likely to find a behaviour attractive if you get to do one of your favourite things at the same time. In the end you may even look forward to do the habit you need as it's related to the habit you want.

feat(habit_management#Align your personal identity change with an existent shared identity): Align your personal identity change with an existent shared identity

We pick up habits from the people around us. As a general rule, the closer we are to someone, the more likely we are to imitate some of their habits. One of the most effective things you can do to build better habits is to join a culture where your desired behaviour is the normal one. This transforms your personal identity transformation into the building of a shared one. Shared identities have great benefits over single ones:

- They foster belonging. A powerful feeling that creates motivation.
- They are more resilient: When one falters others will take their place so all together you'll guarantee the maintenance of the identity.
- They create friendship and community
- They expose you to an environment where more habits tied to that identity thrive.

Likewise, if you're trying to run from a bad habit cut your ties to communities that embrace that habit.

feat(immich): Introduce immich

Self-hosted photo and video backup solution directly from your mobile phone.

References:

- [Home](https://immich.app/)
- [Api](https://immich.app/docs/api)
- [Docs](https://immich.app/docs/overview/introduction)
- [Source](https://github.com/immich-app/immich).
- [Blog](https://immich.app/blog)
- [Demo](https://demo.immich.app/photos)

feat(immich#Installation): Installation

- Create a directory of your choice (e.g. `./immich-app`) to hold the `docker-compose.yml` and `.env` files.

  ```bash
  mkdir ./immich-app
  cd ./immich-app
  ```

- Download `docker-compose.yml`, `example.env` and optionally the `hwaccel.yml` files:

  ```bash
  wget -O docker-compose.yaml https://github.com/immich-app/immich/releases/latest/download/dockr-compose.yml
  wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env
  wget https://github.com/immich-app/immich/releases/latest/download/hwaccel.yml
  ```
- Tweak those files with these thoughts in mind:
  - `immich` won't respect your upload media directory structure, so until you trust the softwar copy your media to the uploads directory.
  - immich is not stable so you need to disable the upgrade from watchtower. The easiest way is to [pin the latest stable version](https://github.com/immich-app/immich/pkgs/container/immich-server/versions?filters%5Bversion_type%5D=tagged) in the `.env` file.
  - Populate custom database information if necessary.
  - Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets.
  - Consider changing `DB_PASSWORD` to something randomly generated

- From the directory you created in Step 1, (which should now contain your customized `docker-compose.yml` and `.env` files) run:

  ```bash
  docker compose up -d
  ```

feat(immich#Configure smart search for other language): Configure smart search for other language

You can change to a multilingual model listed [here](https://huggingface.co/collections/immich-app/multilingual-clip-654eb08c2382f591eeb8c2a7) by going to Administration > Machine Learning Settings > Smart Search and replacing the name of the model.

Choose the one that has more downloads. For example, if you'd want the `
+immich-app/XLM-Roberta-Large-Vit-B-16Plus` model, you should only enter `XLM-Roberta-Large-Vit-B-16Plus` in the program configuration. Be careful not to add trailing whitespaces.

Be sure to re-run Smart Search on all assets after this change. You can then search in over 100 languages.

feat(immich#External storage): External storage

If you have an already existing library somewhere immich is installed you can use an [external library](https://immich.app/docs/guides/external-library). Immich will respect the files on that directory.

It won't create albums from the directory structure. If you want to do that check [this](https://github.com/alvistar/immich-albums) or [this](https://gist.github.com/REDVM/d8b3830b2802db881f5b59033cf35702) solutions.

feat(immich#My personal workflow): My personal workflow

I've tailored a personal workflow given the next thoughts:

- I don't want to expose Immich to the world, at least until it's a stable product.
- I already have in place a sync mechanism with [syncthing](syncthing.md) for all the mobile stuff
- I do want to still be able to share some albums with my friends and family.
- I want some mobile directories to be cleaned after importing the data (for example the `camera/DCIM`), but others should leave the files as they are after the import (OsmAnd+ notes).

Ingesting the files:

As all the files I want to ingest are sent to the server through syncthing, I've created a cron script that copies or moves the required files. Something like:

```bash

date
echo 'Updating the OsmAnd+ data'
rsync -auhvEX --progress /data/apps/syncthing/data/Osmand/avnotes /data/media/pictures/unclassified

echo 'Updating the Camera data'
mv /data/apps/syncthing/data/camera/Camera/* /data/media/pictures/unclassified/

echo 'Cleaning laptop home'
mv /data/media/downloads/*jpeg /data/media/downloads/*jpg /data/media/downloads/*png /data/media/pictures/unclassified/
echo
```

Where :

- `/data/media/pictures/unclassified` is a subpath of my [external library](#external-library).
- The last echo makes sure that the program exits with a return code of `0`. The script is improbable as it only takes into account the happy path, and I'll silently miss errors on it's execution. But as a first iteration it will do the job.

Then run the script in a cron and log the output to [`journald`](journald.md):

```cron
0 0 * * * /bin/bash /usr/local/bin/archive-photos.sh | /usr/bin/logger -t archive_fotos
```

Make sure to configure the update library cron job to run after this script has ended.

feat(immich#Not there yet): Not there yet

There are some features that are still lacking:

- [Image rotation](https://github.com/immich-app/immich/discussions/1695)
- [Smart albums](https://github.com/immich-app/immich/discussions/1673)
- [Image rating](https://github.com/immich-app/immich/discussions/3619)
- [Tags](https://github.com/immich-app/immich/discussions/1651)
- [Nested albums](https://github.com/immich-app/immich/discussions/2073#discussioncomment-6584926)
- [Duplication management](https://github.com/immich-app/immich/discussions/1968)
- [Search guide](https://github.com/immich-app/immich/discussions/3657)

feat(immich#Edit an image metadata): Edit an image metadata

You can't do it directly through the interface yet, use [exiftool](linux_snippets.md#Remove-image-metadata) instead.

This is interesting to remove the geolocation of the images that are not yours

feat(kitty): Suggest to use nerd fonts

If you're thinking of adding a new font, you should take a look at the [nerd fonts](https://www.nerdfonts.com/#home) as they patch developer targeted fonts with a high number of glyphs (icons). Specifically to add a high number of extra glyphs from popular ‘iconic fonts’ such as Font Awesome, Devicons, Octicons, and others.

For example you can get the [`FiraCode Nerd Font`](https://github.com/ryanoasis/nerd-fonts/releases/download/v3.1.1/FiraCode.zip)

feat(lazyvim): Introduce LazyVim

- [Source](https://github.com/LazyVim/LazyVim)
- [Docs](https://lazyvim.github.io/)
- [Home](https://lazyvim.github.io/)

feat(lazyvim#Adding plugins configuration): Adding plugins configuration

Configuring LazyVim plugins is exactly the same as using `lazy.nvim` to build a config from scratch.

For the full plugin spec documentation please check the [lazy.nvim readme](https://github.com/folke/lazy.nvim).

LazyVim comes with a list of preconfigured plugins, check them [here](https://www.lazyvim.org/configuration/plugins) before diving on your own.

feat(lazyvim#Adding a plugin): Adding a plugin

Adding a plugin is as simple as adding the plugin spec to one of the files under `lua/plugins/*.lua``. You can create as many files there as you want.

You can structure your `lua/plugins`` folder with a file per plugin, or a separate file containing all the plugin specs for some functionality. For example: `lua/plugins/lsp.lua`

```lua
return {
  -- add symbols-outline
  {
    "simrat39/symbols-outline.nvim",
    cmd = "SymbolsOutline",
    keys = { { "<leader>cs", "<cmd>SymbolsOutline<cr>", desc = "Symbols Outline" } },
    opts = {
      -- add your options that should be passed to the setup() function here
      position = "right",
    },
  },
}
```

Customizing plugin specs. Defaults merging rules:

- cmd: the list of commands will be extended with your custom commands
- event: the list of events will be extended with your custom events
- ft: the list of filetypes will be extended with your custom filetypes
- keys: the list of keymaps will be extended with your custom keymaps
- opts: your custom opts will be merged with the default opts
- dependencies: the list of dependencies will be extended with your custom dependencies
- any other property will override the defaults

For ft, event, keys, cmd and opts you can instead also specify a values function that can make changes to the default values, or return new values to be used instead.

```lua
-- change trouble config
{
  "folke/trouble.nvim",
  -- opts will be merged with the parent spec
  opts = { use_diagnostic_signs = true },
}

-- add cmp-emoji
{
  "hrsh7th/nvim-cmp",
  dependencies = { "hrsh7th/cmp-emoji" },
  ---@param opts cmp.ConfigSchema
  opts = function(_, opts)
    table.insert(opts.sources, { name = "emoji" })
  end,
}
```

Defining the plugin keymaps:

Adding `keys=` follows the rules as explained above. You don't have to specify a mode for `normal` mode keymaps.

You can also disable a default keymap by setting it to `false`. To override a keymap, simply add one with the same `lhs` and a new `rhs`. For example `lua/plugins/telescope.lua`

```lua
return {
  "nvim-telescope/telescope.nvim",
  keys = {
    -- disable the keymap to grep files
    {"<leader>/", false},
    -- change a keymap
    { "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Find Files" },
    -- add a keymap to browse plugin files
    {
      "<leader>fp",
      function() require("telescope.builtin").find_files({ cwd = require("lazy.core.config").options.root }) end,
      desc = "Find Plugin File",
    },
  },
},
```

Make sure to use the exact same mode as the keymap you want to disable.

```lua
return {
  "folke/flash.nvim",
  keys = {
    -- disable the default flash keymap
    { "s", mode = { "n", "x", "o" }, false },
  },
}
```
You can also return a whole new set of keymaps to be used instead. Or return `{}` to disable all keymaps for a plugin.

```lua
return {
  "nvim-telescope/telescope.nvim",
  -- replace all Telescope keymaps with only one mapping
  keys = function()
    return {
      { "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Find Files" },
    }
  end,
},
```

feat(lazyvim#Auto update plugins): Auto update plugins

Add this to `~/.config/nvim/lua/config/autocomds.lua`

```lua
local function augroup(name)
  return vim.api.nvim_create_augroup("lazyvim_" .. name, { clear = true })
end

vim.api.nvim_create_autocmd("VimEnter", {
  group = augroup("autoupdate"),
  callback = function()
    if require("lazy.status").has_updates then
      require("lazy").update({ show = false })
    end
  end,
})
```

feat(letsencrypt#Manually renew a certificate): Manually renew a certificate

Linuxserver swag container renews the certificates at night. If you don't have your server up at those hours your certificate won't be renewed automatically and you need to react to the prometheus alert manually. To do so get into the container and run `certbot renew`.

feat(life_planning):  Update the month planning

Decide the month objectives:

Create the month objectives in your roadmap file after addressing each element of:

- Your last month review document.
- The trimester objectives of your roadmap.

Once they are ready, copy them to the description of your `todo.org` file. That way you'll see it every day.

For each of your month objectives:

- Decide whether it makes sense to address it this month. If not, archive it
- Create a clear plan of action for this month on that objective
- Define the todo of each device (mobile, tablet, laptop)
- Tweak your *things to think about list*.
- Tweak your *reading list*.
- Tweak your week distribution (what to do in each day)
- If you selected maintenance week days tweak the priorities on your *maintenance list*.
- If you selected improvement week days tweak the priorities on your *improvements list*.
- Tweak your *habit manager system*.

feat(life_review): Use deadlines

Identify hard deadlines: Add a warning days before the deadline to make sure you're reminded until it's done.

feat(linux_snippets#Configure nginx to restrict methods): Configure nginx to restrict methods

```
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        if ($request_method !~ ^(GET|POST)$ ) {
            return 405;
        }

        try_files $uri $uri/ =404;
    }
}
```

feat(linux_snippets#Configure nginx location regexp to accept dashes): Configure nginx location regexp to accept dashes

```
location ~* /share/[\w-]+ {
  root /home/project_root;
}
```

feat(linux_snippets#Configure nginx location to accept many paths): Configure nginx location to accept many paths

```
location ~ ^/(static|media)/ {
  root /home/project_root;
}
```

feat(linux_snippets#Remove image metadata): Remove image metadata

```bash
exiftool -all:all= /path/to/file
```

feat(linux_snippets#Get the size increment of a directory between two dates): Get the size increment of a directory between two dates

To see how much has a directory grown between two dates you can use:

```bash
find /path/to/directory -type f -newerat 2022-12-31 ! -newerat 2024-01-01 -printf "%s\\n" | awk '{s+=$1} END {print s}'
```

It finds all the files in that directory that were created in the 2023, it only prints their size in bytes and then it adds them all up.

feat(loki#Prevent the too many outstanding requests error): Prevent the too many outstanding requests error

Add to your loki config the next options
```yaml

limits_config:
  split_queries_by_interval: 24h
  max_query_parallelism: 100

query_scheduler:
  max_outstanding_requests_per_tenant: 4096

frontend:
  max_outstanding_per_tenant: 4096
```

feat(vim_keymaps): Introduce vim keymaps

LazyVim comes with some sane default keybindings, you can see them [here](https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua). You don't need to remember them all, it also comes with [which-key](https://github.com/folke/which-key.nvim) to help you remember your keymaps. Just press any key like <space> and you'll see a popup with all possible keymaps starting with <space>.

- default `<leader>` is `<space>`
- default `<localleader>` is `\`

General editor bindings:

- Save file: `<C-s>`
- Quit all: `<leader>qq`
- Open a floating terminal: `<C-/>`

Movement keybindings:

- Split the windows:
  - Vertically: `<C-|`
  - Horizontally: `<C--`
- Delete window: `<leader>wd`
- To move around the windows you can use: <C-h>, <C-j>, <C-k>, <C-l>.
- To resize the windows use: <C-Up>, <C-Down>, <C-Left>, <C-Right>
- To move between buffers:
  - Next and previous with <S-h>, <S-l>
  - Switch to the previously opened buffer: `<leader>bb`

Coding keybindings:

Diagnostics:

- `<leader>cd>`: Shows you the diagnostics message of the current line in a floating window
- `]d` and `[d`: iterates over all diagnostics
- `]e` and `[e`: iterates over all error diagnostics
- `]w` and `[w`: iterates over all warning diagnostics

feat(vim_keymaps#Setting keymaps in lua): Setting keymaps in lua

If you need to set keymaps in lua you can use `vim.keymap.set`. For example:

```lua
vim.keymap.set('n', '<space>w', '<cmd>write<cr>', {desc = 'Save'})
```

After executing this, the sequence `Space + w` will call the `write` command. Basically, we can save changes made to a file with `Space + w`.

Let's dive into what does the  `vim.keymap.set` parameters mean.

```lua
vim.keymap.set({mode}, {lhs}, {rhs}, {opts})
```

* `{mode}`:  mode where the keybinding should execute. It can be a list of modes. We need to speify the mode's short name. Here are some of the most common.
  * `n`: Normal mode.
  * `i`: Insert mode.
  * `x`: Visual mode.
  * `s`: Selection mode.
  * `v`: Visual + Selection.
  * `t`: Terminal mode.
  * `o`: Operator-pending.
  * `''`: Yes, an empty string. Is the equivalent of `n + v + o`.

* `{lhs}`: is the key we want to bind.
* `{rhs}` is the action we want to execute. It can be a string with a command or an expression. You can also provide a lua function.
* `{opts}` this must be a lua table. If you don't know what is a "lua table" just think is a way of storing several values in one place. Anyway, it can have these properties.

  * `desc`: A string that describes what the keybinding does. You can write anything you want.
  * `remap`: A boolean that determines if our keybinding can be recursive. The default value is `false`. Recursive keybindings can cause some conflicts if used incorrectly. Don't enable it unless you know what you're doing.
  * `buffer`: It can be a boolean or a number. If we assign the boolean `true` it means the keybinding will only be effective in the current file. If we assign a number, it needs to be the "id" of an open buffer.
  * `silent`: A boolean. Determines whether or not the keybindings can show a message. The default value is `false`.
  * `expr`: A boolean. If enabled it gives the chance to use vimscript or lua to calculate the value of `{rhs}`. The default value is `false`.

feat(vim_keymaps#The leader key): The leader key

When creating keybindings we can use the special sequence `<leader>` in the `{lhs}` parameter, it'll take the value of the global variable `mapleader`.

So `mapleader` is a global variable in vimscript that can be string. For example.

```lua
vim.g.mapleader = ' '
```

After defining it we can use it as a prefix in our keybindings.

```lua
vim.keymap.set('n', '<leader>w', '<cmd>write<cr>')
```

This will make `<space key>` + `w` save the current file.

There are different opinions on what key to use as the `<leader>` key. The `<space>` is the most comfortable as it's always close to your thumbs, and it works well with both hands. Nevertheless, you can only use it in normal mode, because in insert `<space><whatever>` will be triggered as you write. An alternative is to use `;` which is also comfortable (if you use the english key distribution) and you can use it in insert mode.

If you [want to define more than one leader key](https://stackoverflow.com/questions/30467660/can-we-define-more-than-one-leader-key-in-vimrc) you can either:

* Change the `mapleader` many times in your file: As the value of `mapleader` is used at the moment the mapping is defined, you can indeed change that while plugins are loading. For that, you have to explicitly `:runtime` the plugins in your `~/.vimrc` (and count on the canonical include guard to prevent redefinition later):

  ```vim
  let mapleader = ','
  runtime! plugin/NERD_commenter.vim
  runtime! ...
  let mapleader = '\'
  runime! plugin/mark.vim
  ...
  ```
* Use the keys directly instead of using `<leader>`

  ```vim
  " editing mappings
  nnoremap ,a <something>
  nnoremap ,k <something else>
  nnoremap ,d <and something else>

  " window management mappings
  nnoremap gw <something>
  nnoremap gb <something else>
  ```

Defining `mapleader` and/or using `<leader>` may be useful if you change your mind often on what key to use a leader but it won't be of any use if your mappings are stable.

feat(neotree): Introduce neotree

General keymaps:

- `<cr>`: Open the file in the current buffer
- `<s>`: Open in a vertical split
- `<S>`: Open in an horizontal split
- `<bs>`: Navigate one directory up (even if it's the root of the `cwd`)

File and directory management:

- `a`: Create a new file or directory. Add a `/` to the end of the name to make a directory.
- `d`: Delete the selected file or directory
- `r`: Rename the selected file or directory
- `y`: Mark file to be copied (supports visual selection)
- `x`: Mark file to be cut (supports visual selection)
- `m`: Move the selected file or directory
- `c`: Copy the selected file or directory

References:

- [Docs](https://github.com/nvim-neo-tree/neo-tree.nvim/blob/main/doc/neo-tree.txt)
- [Wiki](https://github.com/nvim-neo-tree/neo-tree.nvim/wiki)
- [Wiki Recipes](https://github.com/nvim-neo-tree/neo-tree.nvim/wiki/Recipes)

feat(neotree#Show hidden files): Show hidden files

```lua
return {
  "nvim-neo-tree/neo-tree.nvim",
  opts = {
    filesystem = {
      filtered_items = {
        visible = true,
        show_hidden_count = true,
        hide_dotfiles = false,
        hide_gitignored = true,
        hide_by_name = {
          '.git',
        },
        never_show = {},
      },
    }
  }
}
```

feat(neotree#Autoclose on open file): Autoclose on open file

This example uses the file_open event to close the Neo-tree window when a file is opened. This applies to all windows and all sources at once.

```lua
require("neo-tree").setup({
  event_handlers = {

    {
      event = "file_opened",
      handler = function(file_path)
        -- auto close
        -- vimc.cmd("Neotree close")
        -- OR
        require("neo-tree.command").execute({ action = "close" })
      end
    },

  }
})
```

feat(neotree#Configuring vim folds): Configuring vim folds

Copy the code under [implementation](https://github.com/nvim-neo-tree/neo-tree.nvim/wiki/Recipes#emulating-vims-fold-commands) in your config file.

feat(neotree#Can't copy file/directory to itself): Can't copy file/directory to itself

If you want to copy a directory you need to assume that the prompt is done from within the directory. So if you want to copy it to a new name at the same level you need to use `../new-name` instead of `new-name`.

feat(orgmode#Using lazyvim): Install using lazyvim

```lua
return {
  'nvim-orgmode/orgmode',
  ```lua
    {
        'nvim-orgmode/orgmode',
        dependencies = {
      { 'nvim-treesitter/nvim-treesitter', lazy = true },
    },
        event = 'VeryLazy',
        config = function()
    -- Load treesitter grammar for org
    require('orgmode').setup_ts_grammar()

    -- Setup treesitter
    require('nvim-treesitter.configs').setup({
        highlight = {
          enable = true,
          additional_vim_regex_highlighting = { 'org' },
        },
        ensure_installed = { 'org' },
      })

    -- Setup orgmode
    require('orgmode').setup({
        org_agenda_files = '~/orgfiles/**/*',
        org_default_notes_file = '~/orgfiles/refile.org',
      })
  end,
  }
  ```
  dependencies = {
    { 'nvim-treesitter/nvim-treesitter', lazy = true },
  },
  event = 'VeryLazy',
  config = function()
    -- Load treesitter grammar for org
    require('orgmode').setup_ts_grammar()

    -- Setup treesitter
    require('nvim-treesitter.configs').setup({
      highlight = {
        enable = true,
        additional_vim_regex_highlighting = { 'org' },
      },
      ensure_installed = { 'org' },
    })

    -- Setup orgmode
    require('orgmode').setup({
      org_agenda_files = '~/orgfiles/**/*',
      org_default_notes_file = '~/orgfiles/refile.org',
    })
  end,
}
```

feat(orgmode#Troubleshoot orgmode with dap): Troubleshoot orgmode with dap

Use the next config and follow the steps of [Create an issue in the orgmode repository](orgmode.md#create-an-issue-in-the-orgmode-repository).

```lua
vim.cmd([[set runtimepath=$VIMRUNTIME]])
vim.cmd([[set packpath=/tmp/nvim/site]])

local package_root = '/tmp/nvim/site/pack'
local install_path = package_root .. '/packer/start/packer.nvim'

local function load_plugins()
  require('packer').startup({
    {
      'wbthomason/packer.nvim',
      { 'nvim-treesitter/nvim-treesitter' },
      { 'nvim-lua/plenary.nvim'},
      { 'nvim-orgmode/orgmode'},
      { 'nvim-telescope/telescope.nvim'},
      { 'lyz-code/telescope-orgmode.nvim' },
      { 'jbyuki/one-small-step-for-vimkind' },
      { 'mfussenegger/nvim-dap' },
      { 'kristijanhusak/orgmode.nvim', branch = 'master' },
    },
    config = {
      package_root = package_root,
      compile_path = install_path .. '/plugin/packer_compiled.lua',
    },
  })
end

_G.load_config = function()
  require('orgmode').setup_ts_grammar()
  require('nvim-treesitter.configs').setup({
    highlight = {
      enable = true,
      additional_vim_regex_highlighting = { 'org' },
    },
  })

  vim.cmd([[packadd nvim-treesitter]])
  vim.cmd([[runtime plugin/nvim-treesitter.lua]])
  vim.cmd([[TSUpdateSync org]])

  -- Close packer after install
  if vim.bo.filetype == 'packer' then
    vim.api.nvim_win_close(0, true)
  end

  require('orgmode').setup({
    org_agenda_files = {
      './*'
    }
  }
  )

  -- Reload current file if it's org file to reload tree-sitter
  if vim.bo.filetype == 'org' then
    vim.cmd([[edit!]])
  end
end
if vim.fn.isdirectory(install_path) == 0 then
  vim.fn.system({ 'git', 'clone', 'https://github.com/wbthomason/packer.nvim', install_path })
  load_plugins()
  require('packer').sync()
  vim.cmd([[autocmd User PackerCompileDone ++once lua load_config()]])
else
  load_plugins()
  load_config()
end

require('telescope').setup{
  defaults = {
    preview = {
     enable = true,
      treesitter = false,
    },
    vimgrep_arguments = {
      "ag",
      "--nocolor",
      "--noheading",
      "--numbers",
      "--column",
      "--smart-case",
      "--silent",
      "--follow",
      "--vimgrep",
    },
    file_ignore_patterns = {
      "%.svg",
      "%.spl",
      "%.sug",
      "%.bmp",
      "%.gpg",
      "%.pub",
      "%.kbx",
      "%.db",
      "%.jpg",
      "%.jpeg",
      "%.gif",
      "%.png",
      "%.org_archive",
      "%.flf",
      ".cache",
      ".git/",
      ".thunderbird",
      ".nas",
    },
    mappings = {
      i = {
        -- Required so that folding works when opening a file in telescope
        -- https://github.com/nvim-telescope/telescope.nvim/issues/559
        ["<CR>"] = function()
            vim.cmd [[:stopinsert]]
            vim.cmd [[call feedkeys("\<CR>")]]
        end,
        ['<C-j>'] = 'move_selection_next',
        ['<C-k>'] = 'move_selection_previous',
      }
    }
  },
  pickers = {
    find_files = {
      find_command = { "rg", "--files", "--hidden", "--glob", "!**/.git/*" },
      hidden = true,
      follow = true,
    }
  },
  extensions = {
    fzf = {
      fuzzy = true,                    -- false will only do exact matching
      override_generic_sorter = true,  -- override the generic sorter
      override_file_sorter = true,     -- override the file sorter
      case_mode = "smart_case",        -- or "ignore_case" or "respect_case"
                                       -- the default case_mode is "smart_case"
    },
    heading = {
      treesitter = true,
    },
  }
}

require('telescope').load_extension('orgmode')

local key = vim.keymap
vim.g.mapleader = ' '

local builtin = require('telescope.builtin')
key.set('n', '<leader>f', builtin.find_files, {})
key.set('n', '<leader>F', ':Telescope file_browser<cr>')

vim.api.nvim_create_autocmd('FileType', {
  pattern = 'org',
  group = vim.api.nvim_create_augroup('orgmode_telescope_nvim', { clear = true }),
  callback = function()
    vim.keymap.set('n', '<leader>r', require('telescope').extensions.orgmode.refile_heading)
    vim.keymap.set('n', '<leader>g', require('telescope').extensions.orgmode.search_headings)
  end,
})

require('orgmode').setup_ts_grammar()
local org = require('orgmode').setup({
  org_agenda_files = {
    "./*"
  },
  org_todo_keywords = { 'TODO(t)', 'CHECK(c)', 'DOING(d)', 'RDEACTIVATED(r)', 'WAITING(w)', '|','DONE(e)', 'REJECTED(j)', 'DUPLICATE(u)' },
  org_hide_leading_stars = true,
  org_deadline_warning_days = 0,
  win_split_mode = "horizontal",
  org_priority_highest = 'A',
  org_priority_default = 'C',
  org_priority_lowest = 'D',
  mappings = {
    global = {
      org_agenda = 'ga',
      org_capture = ';c',
    },
    org = {
      -- Enter new items
      org_meta_return = '<c-cr>',
      org_insert_heading_respect_content = ';<cr>',
      org_insert_todo_heading = "<c-t>",
      org_insert_todo_heading_respect_content = ";t",

      -- Heading promoting and demoting
      org_toggle_heading = '<leader>h',
      org_do_promote = '<h',
      org_do_demote = '>h',
      org_promote_subtree = '<H',
      org_demote_subtree = '>H',

      -- Heading moving
      org_move_subtree_up = "<leader>k",
      org_move_subtree_down = "<leader>j",

      -- Heading navigation
      org_next_visible_heading = '<c-j>',
      org_previous_visible_heading = '<c-k>',
      org_forward_heading_same_level = '<c-n>',
      org_backward_heading_same_level = '<c-p>',
      outline_up_heading = 'gp',
      org_open_at_point = 'gx',

      -- State transition
      org_todo = 't',

      -- Priority change
      org_priority_up = '-',
      org_priority_down = '=',

      -- Date management
      org_deadline = '<leader>d',
      org_schedule = '<leader>s',
      org_time_stamp = ';d',
      org_change_date = '<c-e>',

      -- Tag management
      org_set_tags_command = 'T',

      -- Archive management and refiling
      org_archive_subtree = ';a',
      org_toggle_archive_tag = ';A',
      -- org_refile = '<leader>r',  The refile is being handled below
    },
    agenda = {
      org_agenda_later = '<c-n>',
      org_agenda_earlier = '<c-p>',
      org_agenda_switch_to = '<tab>',
      org_agenda_goto = '<cr>',
      org_agenda_priority_up = '=',
      org_agenda_set_tags = 'T',
      org_agenda_deadline = '<leader>d',
      org_agenda_schedule = '<leader>s',
      org_agenda_archive = 'a',
    },
    capture = {
      org_capture_finalize = ';w',
      org_capture_refile = ';r',
      org_capture_kill = 'qqq',
    },
  }
})
local dap = require"dap"
dap.configurations.lua = {
  {
    type = 'nlua',
    request = 'attach',
    name = "Attach to running Neovim instance",
  }
}

dap.adapters.nlua = function(callback, config)
  callback({ type = 'server', host = config.host or "127.0.0.1", port = config.port or 8086 })
end

vim.api.nvim_set_keymap('n', '<leader>b', [[:lua require"dap".toggle_breakpoint()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>c', [[:lua require"dap".continue()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>n', [[:lua require"dap".step_over()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>m', [[:lua require"dap".repl.open()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>N', [[:lua require"dap".step_into()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<F12>', [[:lua require"dap.ui.widgets".hover()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<F5>', [[:lua require"osv".launch({port = 8086})<CR>]], { noremap = true })
```

feat(orgmode#Hide the state changes in the folds): Hide the state changes in the folds

The folding of the recurring tasks iterations is also kind of broken. For the next example

```orgmode
** TODO Recurring task
   DEADLINE: <2024-02-08 Thu .+14d -0d>
   :PROPERTIES:
   :LAST_REPEAT: [2024-01-25 Thu 11:53]
   :END:
   - State "DONE" from "TODO" [2024-01-25 Thu 11:53]
   - State "DONE" from "TODO" [2024-01-10 Wed 23:24]
   - State "DONE" from "TODO" [2024-01-03 Wed 19:39]
   - State "DONE" from "TODO" [2023-12-11 Mon 21:30]
   - State "DONE" from "TODO" [2023-11-24 Fri 13:10]

   - [ ] Do X
```

When folded the State changes is not added to the Properties fold. It's shown something like:

```orgmode
** TODO Recurring task
   DEADLINE: <2024-02-08 Thu .+14d -0d>
   :PROPERTIES:...
   - State "DONE" from "TODO" [2024-01-25 Thu 11:53]
   - State "DONE" from "TODO" [2024-01-10 Wed 23:24]
   - State "DONE" from "TODO" [2024-01-03 Wed 19:39]
   - State "DONE" from "TODO" [2023-12-11 Mon 21:30]
   - State "DONE" from "TODO" [2023-11-24 Fri 13:10]

   - [ ] Do X
```

I don't know if this is a bug or a feature, but when you have many iterations it's difficult to see the task description. So it would be awesome if they could be included into the properties fold or have their own fold.

I've found though that if you set the [`org_log_into_drawer = "LOGBOOK"` in the config](https://github.com/nvim-orgmode/orgmode/issues/455) this is fixed.

feat(orgmode#Things that are still broken or not developed): Things that are still broken or not developed

- [The agenda does not get automatically refreshed](https://github.com/nvim-orgmode/orgmode/issues/656)
- [Uncheck checkboxes on recurring tasks once they are completed](https://github.com/nvim-orgmode/orgmode/issues/655)
- [Foldings when moving items around](https://github.com/nvim-orgmode/orgmode/issues/524)
- [Refiling from the agenda](https://github.com/nvim-orgmode/orgmode/issues/657)
- [Interacting with the logbook](https://github.com/nvim-orgmode/orgmode/issues/149)

feat(photo_self_hosted): Do comparison of selfhosted photo software

There are [many alternatives to self host a photo management software](https://awesome-selfhosted.net/tags/photo-and-video-galleries.html), here goes my personal comparison. You should complement this article with [meichthys one](https://meichthys.github.io/foss_photo_libraries/).

!!! note "TL;DR: I'd first go with Immich, then LibrePhotos and then LycheeOrg"

| Software              | Home-Gallery    | Immich      | LibrePhotos |
| ---                   | ---             | ---         | ---         |
| UI                    | Fine            | Good        |  Fine       |
| Popular (stars)       | 614             | 25k         |  6k         |
| Active (PR/Issues)(1) | ?               | 251/231     |  27/16      |
| Easy deployment       | ?               | True        |  Complicated|
| Good docs             | True            | True        |  True       |
| Stable                | True            | False       |  True       |
| Smart search          | ?               | True        |  True       |
| Language | Javascript | Typescript | Python |
| Batch edit            | True            | True        |  ?          |
| Multi-user            | False           | True        |  ?          |
| Mobile app            | ?               | True        |  ?          |
| Oauth support         | ?               | True        |  ?          |
| Facial recognition    | ?               | True        |  ?          |
| Scales well           | False           | True        |  ?          |
| Favourites            | ?               | True        |  ?          |
| Archive               | ?               | True        |  ?          |
| Has API               | True            | True        |  ?          |
| Map support           | True            | True        |  ?          |
| Video Support         | True            | True        |  ?          |
| Discover similar      | True            | True        |  ?          |
| Static site           | True            | False       |  ?          |

- (1): It refers to the repository stats of the last month

**[Immich](immich.md)**:

References:

- [Home](https://immich.app/)
- [Demo](https://demo.immich.app/photos)
- [Source](https://github.com/immich-app/immich).

Pros:
- Smart search is awesome Oo
- create shared albums that people can use to upload and download
- map with leaflet
- explore by people and places
- docker compose
- optional [hardware acceleration](https://immich.app/docs/features/hardware-transcoding)
- very popular 25k stars, 1.1k forks
- has a [CLI](https://immich.app/docs/features/command-line-interface)
- can [load data from a directory](https://immich.app/docs/features/libraries)
- It has an [android app on fdroid to automatically upload media](https://immich.app/docs/features/mobile-app)
- [sharing libraries with other users](https://immich.app/docs/features/partner-sharing) and with the public
- favorites and archive
- public sharing
- oauth2, specially with [authentik <3](https://immich.app/docs/administration/oauth)
- extensive api: https://immich.app/docs/api/introduction
- It has an UI similar to google photos, so it would be easy for non technical users to use.
- Batch edit
- Discover similar through the smart search

Cons:

- If you want to get results outside the smart search you are going to have a bad time. There is still no way to filter the smart search results or even sort them. You're sold to the AI.
- dev suggests not to use watchtower as the project is in unstable alpha
- Doesn't work well in firefox
- It doesn't work with tags which you don't need because the smart search is so powerful.
- Scans pictures on the file system

**[LibrePhotos](https://docs.librephotos.com/)**:

References:

- [Source](https://github.com/LibrePhotos/librephotos)
- [Docs](https://docs.librephotos.com/docs/intro)
- [Demo](https://demo2.librephotos.com/login)
- [Outdated comparison](https://docs.librephotos.com/docs/user-guide/features)

Pros:

- [docker compose](https://docs.librephotos.com/docs/installation/standard-install), although you need to build the dockers yourself
- [android app](https://docs.librephotos.com/docs/user-guide/mobile/)
- 6k stars, 267 forks
- object, scene ai extraction

Cons:

- Not as good as Immich.

**[Home-Gallery](https://docs.home-gallery.org/general.html)**:

You can see the demo [here](https://demo.home-gallery.org/).

Nice features:

- Simple UI
- Discover similar images
- Static site generator
- Shift click to do batch editing

Cons:

- All users see all media
- The whole database is loaded into the browser and requires recent (mobile) devices and internet connection
- Current tested limits are about 400,000 images/videos

**Lycheeorg**:

References:

- [Home](https://lycheeorg.github.io/)
- [Docs](https://lycheeorg.github.io/docs)
- [Source](https://github.com/LycheeOrg/Lychee)

Pros:

- Sharing like it should be. One click and every photo and album is ready for the public. You can also protect albums with passwords if you want. It's under your control.
- Manual tags
- apparently safe upgrades
- docker compose
- 2.9k stars

Cons:
- demo doesn't show many features
- no ai

**Photoview**:

- [Home](https://photoview.github.io/)
- [Source](https://github.com/photoview/photoview)
- [Docs](https://photoview.github.io/en/docs/usage-people/)

Pros:

- Syncs with file system
- Albums and individual photos or videos can easily be shared by generating a public or password protected link.
- users support
- maps support
- 4.4k stars
- Face recognition

Cons:

- Demo difficult to understand as it's not in english
- mobile app only for ios
- last commit 6 months ago

**Pigallery2**:

References:

- [Home](https://bpatrik.github.io/pigallery2/)

Pros:

- map
- The gallery also supports *.gpx file to show your tracked path on the map too
- App supports full boolean logic with negation and exact or wildcard search. It also provides handy suggestions with autocomplete.
- face recognitiom: PiGallery2 can read face reagions from photo metadata. Current limitation: No ML-based, automatic face detection.
- rating and grouping by rating
- easy query builder
- video transcoding
- blog support. Markdown based blogging support

  You can write some note in the *.md files for every directory

- You can create logical albums (a.k.a.: Saved search) from any search query. Current limitation: It is not possible to create albums from a manually picked photos.
- PiGallery2 has a rich settings page where you can easily set up the gallery.

Cons:
- no ml face recognition

**Piwigo**:

References:

- [Home](piwigo.org)
- [Source](https://github.com/Piwigo/Piwigo)

Piwigo is open source photo management software. Manage, organize and share your photo easily on the web. Designed for organisations, teams and individuals

Pros:

- Thousands of organizations and millions of individuals love using Piwigo
- shines when it comes to classifying thousands or even hundreds of thousands of photos.
- Born in 2002, Piwigo has been supporting its users for more than 21 years. Always evolving!
- You can add photos with the web form, any FTP client ora desktop application like digiKam, Shotwell, Lightroom ormobile applications.
- Filter photos from your collection, make a selection and apply actions in batch: change the author, add some tags, associate to a new album, set geolocation...
- Make your photos private and decide who can see each of them. You can set permissions on albums and photos, for groups or individual users.
- Piwigo can read GPS latitude and longitude from embedded metadata. Then, with plugin for Google Maps or OpenStreetMap, Piwigo can display your photos on an interactive map.
- Change appearance with themes. Add features with plugins. Extensions require just a few clicks to get installed. 350 extensions available, and growing!
- With the Fotorama plugin, or specific themes such as Bootstrap Darkroom, you can experience the full screen slideshow.
- Your visitors can post comments, give ratings, mark photos as favorite, perform searches and get notified of news by email.
- Piwigo web API makes it easy for developers to perform actions from other applications
- GNU General Public License, or GPL
- 2.9 k stars, 400 forks
- still active
- nice release documents: https://piwigo.org/release-14.0.0

Cons:

- Official docs don't mention docker
- no demo: https://piwigo.org/demo
- Unpleasant docs: https://piwigo.org/doc/doku.php
- Awful plugin search: https://piwigo.org/ext/

**[Damselfly](https://damselfly.info/)**:

Fast server-based photo management system for large collections of images. Includes face detection, face & object recognition, powerful search, and EXIF Keyword tagging. Runs on Linux, MacOS and Windows.

Very ugly UI

**[Saigal](https://github.com/saimn/sigal)**:

Too simple

**[Spis](https://github.com/gbbirkisson/spis)**:

Low number of maintainers
Too simple

feat(promtail#Pipeline building): Pipeline building

In [this issue](https://github.com/grafana/loki/issues/6165) there are nice examples on different pipelines.

feat(promtail#Drop logs): Drop logs

If you don't want the logs that have the keyword `systemd-journal` and value `docker-compose` you can add the next pipeline stage:

```yaml
pipeline_stages:
  - drop:
      source: syslog_identifier
      value: docker-compose
```

feat(rich): Adding a footer to a table

Adding a footer is not easy task. [This answer](https://github.com/Textualize/rich/discussions/2135) doesn't work anymore as `table` doesn't have the `add_footer`. You need to create the footer in the `add_column` so you need to have the data that needs to go to the footer before building the rows.

You would do something like:

```python
table = Table(title="Star Wars Movies", show_footer=True)
table.add_column("Title", style="magenta", footer='2342')
```

feat(route_management): Introduce route management

To analyze which hiking routes are available in a zone I'm following the next process

- [ ] Check in my `trips` orgmode directory to see if the zone has already been indexed.
- [ ] Do a first search of routes
  - [ ] Identify which books or magazines describe the zone
  - [ ] For each of the described routes in each of these books:
    - [ ] Create the `Routes` section with tag `:route:` if it doesn't exist
    - [ ] Fill up the route form in a `TODO` heading. Something similar to:
      ~~~
      Reference: Book Page
      Source: Where does it start
      Distance: X km
      Slope: X m
      Type: [Lineal/Circular/Semi-lineal]
      Difficulty:
      Track: URL (only if you don't have to search for it)
      ~~~
    - [ ] Add tags of the people I'd like to do it with
    - [ ] Put a postit on the book/magazine if it's likely I'm going to do it
    - [ ] Open a web maps tab with the source of the route to calculate the time from the different lodgins
  - [ ] If there are not enough, repeat the process above for each of your online route reference blogs

- [ ] Choose the routes to do
  - [ ] Show the gathered routes to the people you want to go with
  - [ ] Select which ones you'll be more likely to do

- [ ] For each of the chosen routes
  - [ ] Search the track in wikiloc if it's missing
  - [ ] Import the track in [OsmAnd+](osmand.md)

feat(vim_config): Configure vim from scratch

Neovim configuration is a **complex** thing to do, both to start and to maintain. The configurations are endless, the plugins are too. Be ready to spend a lot of energy on it and to get lost reading a lot.

If I'm scaring you, you are right to be scared! xD. Once you manage to get it configured to your liking you'll think that in the end it doesn't even matter spending all that time. However if you're searching for something that is plug and play try [vscodium](vscodium.md).

To make things worse, the configuration [is done in lua](#configuration-done-in-Lua), so you may need  a [small refreshment](lua.md) to understand what are you doing.

feat(vim_config#Vim distributions): Vim distributions

One way to make vim's configuration more bearable is to use vim distributions. These are projects that maintain configurations with sane defaults and that work with the whole ecosystem of plugins.

Using them is the best way to:

- Have something usable fast
- Minimize the maintenance efforts as others are doing it for you (plugin changes, breaking changes, ..)
- Keep updated with the neovim ecosystem, as you can see what is the community adding to the default config.

However, there are so many good Neovim configuration distributions that it becomes difficult for a Neovim user to decide which distribution to use and how to tailor it for their use case.

By far, the top 5 Neovim configuration distributions are [AstroNvim](https://github.com/AstroNvim/AstroNvim), [kickstart](https://github.com/nvim-lua/kickstart.nvim), [LazyVim](https://github.com/LazyVim/LazyVim), [LunarVim](https://github.com/LunarVim/LunarVim), and [NvChad](https://github.com/NvChad/NvChad). That is not to say these are the “best” configuration distributions, simply that they are the most popular.

Each of these configuration distributions has value. They all provide excellent starting points for crafting your own custom configuration, they are all extensible and fairly easy to learn, and they all provide an out-of-the-box setup that can be used effectively without modification.

Distinguishing features of the top Neovim configuration distributions are:

- AstroNvim:

    - An excellent community repository
    - Fully featured out-of-the-box
    - Good documentation

- kickstart

    - Minimal out-of-the-box setup
    - Easy to extend and widely used as a starting point
    - A good choice if your goal is hand-crafting your own config

- LazyVim

    - Very well maintained by the author of lazy.nvim
    - Nice architecture, it’s a plugin with which you can import preconfigured plugins
    - Good documentation

- LunarVim

    - Well maintained and mature
    - Custom installation processs installs LunarVim in an isolated location
    - Been around a while, large community, widespread presence on the web

- NvChad

    - Really great base46 plugin enables easy theme/colorscheme management
    - Includes an impressive mappings cheatsheet
    - ui plugin and nvim-colorizer

Personally I tried LunarVim and finally ended up with LazyVim because:

- It's more popular
- I like the file structure
- It's being maintained by [folke](https://github.com/folke) one of the best developers of neovim plugins.

feat(vim_config#Starting your configuration with LazyVim): Starting your configuration with LazyVim

[Installing the requirements](https://www.lazyvim.org/):

LazyVim needs the next tools to be able to work:

- Neovim >= 0.9.0 (needs to be built with LuaJIT). Follow [these instructions](vim.md#installation)
- Git >= 2.19.0 (for partial clones support). `sudo apt-get install git`.
- a [Nerd Font(v3.0 or greater)](https://www.nerdfonts.com/) (optional, but strongly suggested as they rae needed to display some icons). Follow [these instructions if you're using kitty](kitty.md#fonts).
- lazygit (optional and I didn't like it)
- a C compiler for nvim-treesitter. `apt-get install gcc`
- for telescope.nvim (optional)
  - live grep: `ripgrep`
  - find files: `fd`
- a terminal that support true color and undercurl:
  - [kitty (Linux & Macos)](kitty.md)
  - wezterm (Linux, Macos & Windows)
  - alacritty (Linux, Macos & Windows)
  - iterm2 (Macos)

[Install the starter](https://www.lazyvim.org/installation):

- Make a backup of your current Neovim files:
    ```bash
    # required
    mv ~/.config/nvim{,.old}

    # optional but recommended
    mv ~/.local/share/nvim{,.old}
    mv ~/.local/state/nvim{,.old}
    mv ~/.cache/nvim{,.old}
    ```
- Clone the starter

    ```bash
    git clone https://github.com/LazyVim/starter ~/.config/nvim
    ```

- Remove the `.git` folder, so you can add it to your own repo later

    ```bash
    rm -rf ~/.config/nvim/.git
    ```

- Start Neovim!

    ```bash
    nvim
    ```
- It is recommended to run `:LazyHealth` after installation. This will load all plugins and check if everything is working correctly.

[Understanding the file structure](https://www.lazyvim.org/configuration):

The files under `config` will be automatically loaded at the appropriate time, so you don't need to require those files manually.

You can add your custom plugin specs under `lua/plugins/`. All files there will be automatically loaded by lazy.nvim.

```
~/.config/nvim
├── lua
│   ├── config
│   │   ├── autocmds.lua
│   │   ├── keymaps.lua
│   │   ├── lazy.lua
│   │   └── options.lua
│   └── plugins
│       ├── spec1.lua
│       ├── **
│       └── spec2.lua
└── init.toml
```
The files `autocmds.lua`, `keymaps.lua`, `lazy.lua` and `options.lua` under `lua/config` will be automatically loaded at the appropriate time, so you don't need to require those files manually. LazyVim comes with a set of default config files that will be loaded before your own.

You can continue your config by [adding plugins](lazyvim.md).

feat(vim_dap): Introduce Debug Adapter Protocol

`nvim-dap`](https://github.com/mfussenegger/nvim-dap) implements a client for the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/overview). This allows a client to control a debugger over a documented API. That allows us to control the debugger from inside neovim, being able to set breakpoints, evaluate runtime values of variables, and much more.

`nvim-dap` is not configured for any language by default. You will need to set up a configuration for each language. For the configurations you will need adapters to run.

I would suggest starting with 2 actions. Setting breakpoints and “running” the debugger. The debugger allows us to stop execution and look at the current state of the program. Setting breakpoints will allow us to stop execution and see what the current state is.

```lua
vim.api.nvim_set_keymap('n', '<leader>b', [[:lua require"dap".toggle_breakpoint()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>c', [[:lua require"dap".continue()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>n', [[:lua require"dap".step_over()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<leader>N', [[:lua require"dap".step_into()<CR>]], { noremap = true })
vim.api.nvim_set_keymap('n', '<F5>', [[:lua require"osv".launch({port = 8086})<CR>]], { noremap = true })
```

Go to a line where a conditional or value is set and toggle a breakpoint. Then, we’ll start the debugger. If done correctly, you’ll see an arrow next to your line of code you set a breakpoint at.

There is no UI with dap by default. You have a few options for UI [nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui)

In the `dap` repl you can [use the next operations](https://github.com/mfussenegger/nvim-dap/blob/master/doc/dap.txt):

- `.exit`: Closes the REPL
- `.c` or `.continue`: Same as |`dap.continue`|
- `.n` or `.next`: Same as |`dap.step_over`|
- `.into`: Same as |`dap.step_into`|
- `.into_target`: Same as |`dap.step_into{askForTargets=true}`|
- `.out`: Same as |`dap.step_out`|
- `.up`: Same as |`dap.up`|
- `.down`: Same as |`dap.down`|
- `.goto`: Same as |`dap.goto_`|
- `.scopes`: Prints the variables in the current s`cope`s
- `.threads`: Prints all t`hread`s
- `.frames`: Print the stack f`rame`s
- `.capabilities`: Print the capabilities of the debug a`dapte`r
- `.b` or `.back`: Same as |`dap.step_back`|
- `.rc` or `.reverse-continue`: Same as |`dap.reverse_continue`|

feat(vim_dap#nvim-dap-ui): Introduce nvim-dap-ui

Install with packer:

```lua
use { "rcarriga/nvim-dap-ui", requires = {"mfussenegger/nvim-dap"} }
```

It is highly recommended to use [`neodev.nvim`](https://github.com/folke/neodev.nvim) to enable type checking for `nvim-dap-ui` to get type checking, documentation and autocompletion for all API functions.

```lua
require("neodev").setup({
  library = { plugins = { "nvim-dap-ui" }, types = true },
  ...
})
```
`nvim-dap-ui` is built on the idea of "elements". These elements are windows which provide different features.

Elements are grouped into layouts which can be placed on any side of the screen. There can be any number of layouts, containing whichever elements desired.

Elements can also be displayed temporarily in a floating window.

Each element has a set of mappings for element-specific possible actions, detailed below for each element. The total set of actions/mappings and their default shortcuts are:

- edit: `e`
- expand: `<CR>` or left click
- open: `o`
- remove: `d`
- repl: `r`
- toggle: `t`

See `:h dapui.setup()` for configuration opt…
@LonelyMusicDisc
Copy link

Exiting out of insert re-folds the heading I'm in when when in Overview mode, which is very annoying.

@gerazov
Copy link
Contributor

gerazov commented Feb 27, 2024

So quick update for me, folding works fine when the file is newly opened, and I found after some searching that zx updates the folds correctly and will work, it's just a matter of the folds not being auto updated when entering/leaving insert mode occasionally for whatever reason.

Thanks for the tip - I was reloading the file using :e to get the folds to align ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants