Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions readme/KeyboardShortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,101 @@ A compact summary of the function-key family (most frequent collisions):

---

## Cheatsheet — caret & view navigation

A single-stop reference for moving the caret, scrolling the view, and jumping between document landmarks. Repeats keys already listed in the topical sections above so the cheatsheet stands alone. Notepad3 inherits Scintilla's default keymap unchanged (no `SCI_ASSIGNCMDKEY` overrides), so the standard caret bindings below all work even though they are not part of Notepad3's accelerator table.

### Caret movement (basics)

| Shortcut | Action |
|---|---|
| `←` / `→` | Char left / right |
| `↑` / `↓` | Line up / down |
| `Home` / `End` | Line start / end |
| `Ctrl+Home` / `Ctrl+End` | Document start / end |
| `PageUp` / `PageDown` | Page up / down |
| `Shift+`*movement* | Extend selection in that direction |
| `Ctrl+Shift+`*movement* | Extend selection by word / document chunk |

### Word navigation

| Shortcut | Action |
|---|---|
| `Ctrl+←` / `Ctrl+→` | Caret one word left / right |
| `Ctrl+Backspace` | Delete word before caret |
| `Ctrl+Del` | Delete word after caret |
| `Ctrl+Alt+A` | Toggle **Accelerated Word Navigation** (see below) |
| `Ctrl+Space` | Select word at caret (full line if word already selected) |
| `Ctrl+Shift+Space` | Multi-select all matches of word at caret |

**Accelerated Word Navigation** (`Ctrl+Alt+A`) merges punctuation into the word-character set, so word-jump keys (`Ctrl+←`, `Ctrl+→`, `Ctrl+Backspace`, `Ctrl+Del`) skip whole code tokens at once.

Example — caret stops in `foo->bar.baz` walking with `Ctrl+→`:

- off: `foo`  |  `->`  |  `bar`  |  `.`  |  `baz` (5 stops)
- on: `foo->bar.baz` (1 stop)

Fine-tune which characters still break words via `[Settings2] ExtendedWhiteSpaceChars=` — see [`config/Configuration.md`](config/Configuration.md). The toggle is persisted in `[Settings] AccelWordNavigation=`.

### View / scroll

| Shortcut | Action |
|---|---|
| `Ctrl+↑` / `Ctrl+↓` | Scroll one line up / down (caret stays put) |
| `Ctrl+PgUp` / `Ctrl+PgDn` | Goto previous / next block (paragraph or fold) |
| `Ctrl+Shift+PgUp` / `Ctrl+Shift+PgDn` | Select to previous / next block |
| `Alt+PageUp` / `Alt+PageDown` | Paragraph navigation up / down |
| `Ctrl+Alt+V` | Focused View — show only lines matching word/selection |
| `Ctrl+G` | Goto line / column dialog |

### Bookmarks & change history

| Shortcut | Action |
|---|---|
| `F2` | Goto next bookmark — falls through to next change-history marker if no further bookmark is found (sticky) |
| `Shift+F2` | Goto previous bookmark — same fallback |
| `Ctrl+F2` | Toggle bookmark on current line |
| `Alt+F2` | Clear all bookmarks |

If the document has no bookmarks (or none ahead of the caret in the search direction), `F2` / `Shift+F2` walk **change-history markers** instead — modified, saved, and reverted lines shown in the change-history margin (see *View → Change History*). Once a press has landed the caret on a change-history marker, repeated presses keep walking change-history markers until you reach a bookmarked line.

### Find navigation

| Shortcut | Action |
|---|---|
| `F3` | Find next |
| `Shift+F3` | Find previous |
| `Ctrl+F3` | Find next occurrence of current selection |
| `Ctrl+Shift+F3` | Find previous occurrence of current selection |
| `F4` | Replace next |
| `Ctrl+Alt+F2` | Expand selection to next match |
| `Ctrl+Alt+Shift+F2` | Expand selection to previous match |
| `Alt+A` | Toggle "mark all occurrences" of current word |

### Brace navigation

| Shortcut | Action |
|---|---|
| `Ctrl+B` | Find matching brace (or jump to nearest enclosing opening brace) |
| `Ctrl+Shift+B` | Select to matching brace; repeated presses expand the selection outward one nesting level at a time |

### Folding

| Shortcut | Action |
|---|---|
| `Alt+←` / `Alt+→` | Collapse / expand current fold |
| `Alt+-` / `Alt++` | Jump to previous / next fold point |
| `Ctrl+Alt+F` | Toggle all folds |

### Selection-boundary jumps

| Shortcut | Action |
|---|---|
| `Ctrl+,` | Jump caret to selection start |
| `Ctrl+.` | Jump caret to selection end |

---

## See also

- [`faq/FAQ.md`](faq/FAQ.md) — *"Migrating from Notepad2"* lists every shortcut whose meaning was reassigned, plus the **why**.
Expand Down
43 changes: 43 additions & 0 deletions readme/tinyexprcpp/TinyExprPP.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,44 @@ When *Evaluate TinyExpr on Selection* is enabled, selecting any text containing

**Multi-selection / rectangular selection** is supported — selected values are concatenated and evaluated as a single expression.

#### Output modes — decimal · hexadecimal · binary

The TinyExpr status field can display the result in three integer-result formats. The active mode applies to every subsequent evaluation, and is **process-local** — it resets to *decimal* on the next Notepad3 launch.

| Mode | Example output | Notes |
|------|----------------|-------|
| Decimal *(default)* | `15`, `3.14`, `Inf` | Existing format; integers use up to 21 significant digits, floats `%.8G`. |
| Hexadecimal | `0xF`, `0xFF`, `0xFFFFFFFF` | Uppercase, no padding. |
| Binary | `0b1111`, `0b11111111` | Lowercase `b` prefix, no padding. |

In hex / binary, fractional results are rounded to the nearest integer (round-half-away-from-zero). Negative values are shown in **two's-complement** (`-1` → `0xFFFFFFFF` / 32 ones). Values outside the supported integer range, `NaN`, and `Inf` fall back to the decimal `%.8G` representation for that single evaluation.

**Effective bit width** is chosen at runtime via `te_supports_64bit()` — currently 32 bits on the standard MSVC build (where the parser's `double` has a 53-bit mantissa). The display widens automatically to 64 bits if the parser is ever rebuilt with a 64-bit-precise numeric type.

**Empty selection placeholder** also reflects the active mode: `--`, `0x--`, or `0b--`.

**Parse error indicator** carries the same prefix: a syntax error at column N is shown as `^[N]` (decimal), `0x^[N]` (hex), or `0b^[N]` (binary).

#### Status-bar gestures on the TinyExpr field

| Gesture | Action |
|---------|--------|
| **Single left-click** | Copies the currently displayed result (in the active mode) to the clipboard. The copy is debounced by the system double-click interval, so a follow-up double-click cancels the copy. |
| **Double-click** | Cycles output mode: *Decimal → Hexadecimal → Binary → Decimal …* The status field refreshes immediately. |
| **Right-click** | Standard status-bar context menu (unchanged). |

#### Binary input

Expressions may also **use** binary literals `0b…` (or `0B…`), in addition to the always-supported decimal, scientific, and hex (`0x…`) literals. They round-trip the binary output mode:

```
0b101010=? → 42
0xFF + 0b1=? → 256
BITAND(0b1100, 0b1010)=? → 8
```

Binary literals are recognized only at token-start positions, so identifiers like `var0b1` are not affected.

### 3. Go to Line / Column Dialog

The **Go to Line** dialog (Ctrl+G) accepts expressions, not just numbers:
Expand Down Expand Up @@ -76,9 +114,12 @@ The Dark Mode highlight contrast value in the Customize Schemes dialog accepts e
| Decimal | `3.14` | 3.14 |
| Leading dot | `.5` | 0.5 |
| Hexadecimal | `0x1F` | 31 |
| Binary | `0b101010` | 42 |
| Scientific | `1e3` | 1000 |
| Negative scientific | `2.5e-2` | 0.025 |

> Binary literals (`0b…` / `0B…`) are a Notepad3 extension on top of TinyExpr++ — they are rewritten to decimal before the parser sees them.

### Operators (by Precedence)

From highest to lowest precedence:
Expand Down Expand Up @@ -265,9 +306,11 @@ SQRT(3^2 + 4^2)=? → 5

```
0xFF=? → 255
0b101010=? → 42
2^16 - 1=? → 65535
BITLSHIFT(1, 20)=? → 1048576 (1 MB in bytes)
BITAND(0xF0, 0x3C)=? → 48
BITAND(0b1100, 0b1010)=? → 8
```

### Line Numbering (Modify Lines Dialog)
Expand Down
70 changes: 54 additions & 16 deletions src/Edit.c
Original file line number Diff line number Diff line change
Expand Up @@ -10072,27 +10072,61 @@ void EditSetBookmarkList(HWND hwnd, LPCWSTR pszBookMarks)

#define NOT_FOUND_LN ((DocLn)-1)

static int _RespectLastSearch(const int bitmask, const DocLn iLine)
// Sticky-state for F2/Shift+F2 dual bookmark/change-history navigation.
// Module-scope so EditBookmarkResetNavigation can clear them on document load
// and EditBookmarkAdjustNavigation can shift the line index across edits.
static int s_LastSearchBitmask = BOOKMARK_BITMASK();
static DocLn s_LastSearchStart = NOT_FOUND_LN;


void EditBookmarkResetNavigation(void)
{
static int _LastSearchBitmask = BOOKMARK_BITMASK();
static DocLn _LastSearchStart = NOT_FOUND_LN;
s_LastSearchBitmask = BOOKMARK_BITMASK();
s_LastSearchStart = NOT_FOUND_LN;
}


void EditBookmarkAdjustNavigation(const DocLn modLine, const DocLn linesAdded)
{
if (s_LastSearchStart == NOT_FOUND_LN) {
return;
}
if (modLine <= s_LastSearchStart) {
DocLn const shifted = s_LastSearchStart + linesAdded;
if (shifted < 0) {
// Sticky line was removed by the deletion: drop sticky state.
s_LastSearchStart = NOT_FOUND_LN;
}
else {
s_LastSearchStart = shifted;
}
}
}

if (iLine == _LastSearchStart) {
if (bitmask & _LastSearchBitmask) {
return _LastSearchBitmask; // respect last found bitmask

static int _RespectLastSearch(const int bitmask, const DocLn iLine)
{
if (iLine == s_LastSearchStart) {
if (bitmask & s_LastSearchBitmask) {
return s_LastSearchBitmask; // respect last found bitmask
}
}
if (bitmask & BOOKMARK_BITMASK()) {
_LastSearchBitmask = BOOKMARK_BITMASK(); // BOOKMARKS got prio
s_LastSearchBitmask = BOOKMARK_BITMASK(); // BOOKMARKS got prio
}
else {
_LastSearchBitmask = bitmask ? bitmask : BOOKMARK_BITMASK();
s_LastSearchBitmask = bitmask ? bitmask : BOOKMARK_BITMASK();
}
_LastSearchStart = iLine;
return _LastSearchBitmask;
s_LastSearchStart = iLine;
return s_LastSearchBitmask;
}


// Linear-scan fallback for change-history markers.
// Scintilla's SCI_MARKERNEXT walks LineMarkers only (scintilla/src/PerLine.cxx).
// Change-history markers (IDs 21-24) live in the separate change-history machinery
// and are reported via SCI_MARKERGET per-line but are NOT in LineMarkers, so we
// must linear-scan when the bitmask requests them.
static inline DocLn _MarkerNext(const DocLn iLine, const int bitmask)
{
if (bitmask & CHANGE_HISTORY_MARKER_BITMASK()) {
Expand All @@ -10112,6 +10146,8 @@ void EditBookmarkNext(HWND hwnd, DocLn iLine)
{
UNREFERENCED_PARAMETER(hwnd);

DocLn const iStartLn = iLine; // immune to consecutive-marker-skip mutation below

int bitmask = _RespectLastSearch(SciCall_MarkerGet(iLine), iLine);
DocLn iNextLine = _MarkerNext(iLine + 1, bitmask);

Expand All @@ -10122,22 +10158,22 @@ void EditBookmarkNext(HWND hwnd, DocLn iLine)
}
}

if ((iNextLine == NOT_FOUND_LN) && (iLine > 0)) {
if ((iNextLine == NOT_FOUND_LN) && (iStartLn > 0)) {
iNextLine = _MarkerNext(0, bitmask); // wrap around
}

if (iNextLine == NOT_FOUND_LN) { // find any bookmark
bitmask = ALL_MARKERS_BITMASK();
iNextLine = _MarkerNext(iLine + 1, bitmask);
if ((iNextLine == NOT_FOUND_LN) && (iLine > 0)) {
if ((iNextLine == NOT_FOUND_LN) && (iStartLn > 0)) {
iNextLine = _MarkerNext(0, bitmask); // wrap around
}
}

if (iNextLine == NOT_FOUND_LN) { // find change history marker
bitmask = CHANGE_HISTORY_MARKER_BITMASK();
iNextLine = _MarkerNext(iLine + 1, bitmask);
if ((iNextLine == NOT_FOUND_LN) && (iLine > 0)) {
if ((iNextLine == NOT_FOUND_LN) && (iStartLn > 0)) {
iNextLine = _MarkerNext(0, bitmask); // wrap around
}
}
Expand All @@ -10152,6 +10188,7 @@ void EditBookmarkNext(HWND hwnd, DocLn iLine)
//
// EditBookmarkPrevious()
//
// Linear-scan fallback for change-history markers; see _MarkerNext above.
static inline DocLn _MarkerPrevious(const DocLn iLine, const int bitmask)
{
if (bitmask & CHANGE_HISTORY_MARKER_BITMASK()) {
Expand All @@ -10170,6 +10207,7 @@ void EditBookmarkPrevious(HWND hwnd, DocLn iLine)
UNREFERENCED_PARAMETER(hwnd);

DocLn const docLnCount = SciCall_GetLineCount();
DocLn const iStartLn = iLine; // immune to consecutive-marker-skip mutation below

int bitmask = _RespectLastSearch(SciCall_MarkerGet(iLine), iLine);
iLine = (iLine <= 0) ? docLnCount + 1 : iLine;
Expand All @@ -10182,22 +10220,22 @@ void EditBookmarkPrevious(HWND hwnd, DocLn iLine)
}
}

if ((iPrevLine == NOT_FOUND_LN) && (iLine < docLnCount)) {
if ((iPrevLine == NOT_FOUND_LN) && (iStartLn < docLnCount)) {
iPrevLine = _MarkerPrevious(docLnCount, bitmask); // wrap around
}

if (iPrevLine == NOT_FOUND_LN) { // find any bookmark
bitmask = ALL_MARKERS_BITMASK();
iPrevLine = _MarkerPrevious(iLine - 1, bitmask);
if ((iPrevLine == NOT_FOUND_LN) && (iLine < docLnCount)) {
if ((iPrevLine == NOT_FOUND_LN) && (iStartLn < docLnCount)) {
iPrevLine = _MarkerPrevious(docLnCount, bitmask); // wrap around
}
}

if (iPrevLine == NOT_FOUND_LN) { // find change history marker
bitmask = CHANGE_HISTORY_MARKER_BITMASK();
iPrevLine = _MarkerPrevious(iLine - 1, bitmask);
if ((iPrevLine == NOT_FOUND_LN) && (iLine < docLnCount)) {
if ((iPrevLine == NOT_FOUND_LN) && (iStartLn < docLnCount)) {
iPrevLine = _MarkerPrevious(docLnCount, bitmask); // wrap around
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/Edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ void EditSetBookmarkList(HWND hwnd,LPCWSTR pszBookMarks);
void EditBookmarkNext(HWND hwnd, const DocLn iLine);
void EditBookmarkPrevious(HWND hwnd, const DocLn iLine);
void EditBookmarkToggle(HWND hwnd, const DocLn ln, const int modifiers);
void EditBookmarkResetNavigation(void);
void EditBookmarkAdjustNavigation(const DocLn modLine, const DocLn linesAdded);
void EditMarkAllOccurrences(HWND hwnd, bool bForceClear);
void EditFoldMarkedLineRange(HWND hwnd, bool bHideLines);
void EditBookMarkLineRange(HWND hwnd);
Expand Down
Loading
Loading