# Keyboard Shortcuts

You can change *Lx* shortcuts in your user settings.

Open the command palette and run `core:edit-user-settings`.

Save the file when you are done. *Lx* reloads it for you.

## A simple shortcut

This makes Ctrl+Shift+Alt+O open your user settings:

```lua
keymap.bind({
	global = {
		["ctrl+shift+alt+o"] = "core:edit-user-settings",
	},
})
```

There are three parts:

- `global` says where the shortcut works
- `ctrl+shift+alt+o` is the key combination
- `core:edit-user-settings` is the action *Lx* runs

You can place several shortcuts in the same group:

```lua
keymap.bind({
	text_editor = {
		["ctrl+g"] = "doc:go-to-line",
		["ctrl+s"] = "doc:save",
	},
})
```

## Where a shortcut works

A shortcut belongs to a context. The context keeps it away from parts of *Lx* where it would make no sense.

Use the narrowest suitable context.

| Context | Where it works |
|---|---|
| `global` | Throughout *Lx* |
| `text_editor` | While editing text |
| `text_viewer` | While viewing read-only text |
| `doc_view` | In document editors and viewers |
| `command_view` | In the command palette and other prompts |
| `browser` | In the Browser |
| `project_search` | In Search Results |
| `log_view` | In the Log view |
| `binary_viewer` | In the binary viewer |
| `image_viewer` | In the image viewer |
| `ansi_preview` | In the ANSI art preview |
| `tetris` | In Tetris |

For example, saving belongs in `text_editor`. A shortcut that opens your settings can be `global`.

```lua
keymap.bind({
	global = {
		["ctrl+shift+alt+o"] = "core:edit-user-settings",
	},
	text_editor = {
		["ctrl+s"] = "doc:save",
	},
})
```

## Key names

Write modifiers first, joined with `+`:

```text
ctrl+s
ctrl+shift+s
alt+home
shift+pageup
```

*Lx* accepts Ctrl, Shift, Alt, AltGr, and Command. Command is mainly for macOS.

Common key names include:

```text
enter
escape
tab
space
backspace
delete
insert
home
end
pageup
pagedown
up
down
left
right
f1, f2, and the other function keys
```

Mouse buttons and the wheel can also be used:

```text
lclick
mclick
rclick
xclick1
xclick2
wheelup
wheeldown
```

*Lx* puts modifiers into a consistent order for you.

## Replacing a shortcut

Use `keymap.bind` when you want a key to run a particular action.

```lua
keymap.bind({
	text_editor = {
		["ctrl+d"] = "doc:select-occurrence",
	},
})
```

Your binding replaces bindings supplied by plugins and *Lx* core in that context.

## Trying more than one action

A key may list several actions:

```lua
keymap.bind({
	text_editor = {
		["alt+up"] = {
			"autocomplete:previous",
			"doc:outline-previous",
		},
	},
})
```

*Lx* tries them from top to bottom. It stops when one action handles the key.

This is useful when the first action only works in a temporary situation. In this example, Alt+Up moves through autocomplete choices when they are open. Otherwise, it moves to the previous outline item.

If you want every action to run, make a [Custom Command](custom_commands.md) instead.

## Swapping two shortcuts

Use `keymap.swap` when two existing keys should trade places.

```lua
keymap.swap({
	text_editor = {
		["ctrl+d"] = "alt+d",
	},
})
```

You only name the pair once. The swap works in both directions.

*Lx* swaps the complete action lists. This includes extra actions added by plugins.

The two keys must already have bindings in weaker layers of the same context. If either key is free, *Lx* shows an error instead of guessing.

Do not also bind, unbind, extend, unextend, move, or copy either key at the same user, plugin, or core level. *Lx* rejects that conflict so the result cannot depend on line order.

## Moving a shortcut

Use `keymap.move` when an existing shortcut should use a new key.

```lua
keymap.move({
	text_editor = {
		["ctrl+g"] = "ctrl+shift+g",
	},
})
```

This moves everything from Ctrl+G to Ctrl+Shift+G. You do not need to find or repeat the action names.

Ctrl+G becomes free. Anything previously assigned to Ctrl+Shift+G is replaced.

Use `keymap.swap` instead when both keys should remain in use and simply trade places.

Both keys must be in the same context. The old shortcut must already have a binding from a plugin or *Lx* itself. If it does not, *Lx* shows a clear error and changes nothing.

Do not also bind, unbind, extend, unextend, swap, or copy either key at the same user, plugin, or core level. *Lx* rejects the conflict so the result stays predictable.

## Copying a shortcut

Use `keymap.copy` when both the old and new key should run the same existing actions.

```lua
keymap.copy({
	text_editor = {
		["ctrl+g"] = "ctrl+shift+g",
	},
})
```

Ctrl+G keeps working. Ctrl+Shift+G receives the same complete action list.

Anything previously assigned to Ctrl+Shift+G is replaced. You do not need to find or repeat the action names.

Both keys must be in the same context. The old shortcut must already have a binding from a plugin or *Lx* itself. If it does not, *Lx* shows a clear error and changes nothing.

As with move and swap, do not change either key again at the same user, plugin, or core level.

## Disabling a shortcut

Use `keymap.unbind` to leave a key with no action:

```lua
keymap.unbind({
	text_editor = {
		"ctrl+q",
		"ctrl+w",
	},
})
```

Unlike `bind`, the shortcuts are written as a simple list.

## Adding another action

Use `keymap.extend` when you want to keep the existing actions and add another one:

```lua
keymap.extend({
	text_editor = {
		["ctrl+d"] = "my-command:try-first",
	},
})
```

*Lx* tries the added action before inherited actions.

You can add several actions:

```lua
keymap.extend({
	text_editor = {
		["ctrl+d"] = {
			"my-command:first",
			"my-command:second",
		},
	},
})
```

## Removing one action from a key

Use `keymap.unextend` when a key should keep its other actions:

```lua
keymap.unextend({
	text_editor = {
		["ctrl+d"] = "plugin-command:extra-action",
	},
})
```

This removes only the named action. It does not empty the whole shortcut.

## User, plugin, and core bindings

Most people can omit the layer name. *Lx* then treats the change as a user choice.

```lua
keymap.bind({
	text_editor = {
		["ctrl+s"] = "doc:save",
	},
})
```

*Lx* uses this order:

1. Temporary modal shortcuts
2. Your shortcuts
3. Plugin shortcuts
4. *Lx* core shortcuts

Your choices therefore replace plugin and core choices.

Plugin authors and advanced setups can name a layer:

```lua
keymap.bind("plugin", {
	text_editor = {
		["ctrl+d"] = "my-plugin:action",
	},
})
```

The same form works with every operation:

```lua
keymap.swap("plugin", {
	text_editor = {
		["ctrl+d"] = "alt+d",
	},
})
```

This also works with `keymap.move` and `keymap.copy`:

```lua
keymap.move("plugin", {
	text_editor = {
		["ctrl+g"] = "ctrl+shift+g",
	},
})
```

A swap, move, or copy reads the choices below its own level. A user change reads plugin and *Lx* bindings. A plugin change reads *Lx* bindings.

## Several contexts at once

One call can contain several groups:

```lua
keymap.bind({
	global = {
		["f1"] = "browser:toggle",
	},
	text_editor = {
		["ctrl+g"] = "doc:go-to-line",
	},
	browser = {
		["ctrl+down"] = "browser:select-next",
	},
})
```

Keep each key with the part of *Lx* that uses it. This prevents a shortcut from unexpectedly taking over elsewhere.

## Finding action names

Action names usually contain a section and an action:

```text
doc:save
browser:toggle
project-search:find
core:edit-user-settings
```

Open the command palette to search the actions available in your copy of *Lx*.

You can also run either of these actions:

```text
keybinds:generate-txt
keybinds:generate-md
```

They open a list of the current shortcuts. The list shows the final result and the layers that contributed to it.

## If something goes wrong

Save errors appear in the Log view.

Common causes are:

- A missing comma
- A key name without quotes
- A command name without quotes
- A shortcut placed directly below `keymap.bind` instead of inside a context
- A swap where one key has no inherited binding
- A swap that uses the same key twice
- A swap mixed with another operation on the same key and layer
- A move whose old key has no existing binding
- A move that uses the same key more than once
- A move mixed with another operation on the same key and layer
- A copy whose old key has no existing binding
- A copy that uses the same key more than once
- A copy mixed with another operation on the same key and layer

If needed, place `--` at the start of a line to turn it off temporarily:

```lua
-- ["ctrl+d"] = "doc:select-occurrence",
```

Save again after correcting the line. *Lx* will reload the settings.
