docs: rewrite USAGE in the thematic style and expand README
This commit is contained in:
1 parent
68e4ace92b
commit
da2a73d70f
2 files changed
+159
-56
No files matched your search
@@ -1,8 +1,13 @@
|
||||
# YKanBan
|
||||
|
||||
A personal, local/offline kanban board. Cross-platform desktop app built with Avalonia UI and MVVM. Each workspace stores its data in a `.ykanban` folder at the project root, Git-style.
|
||||
A personal, local/offline kanban board. Cross-platform desktop app built with Avalonia UI and MVVM. Each workspace stores its data in a `.ykanban` folder at the project root, Git-style; start it with `ykanban <path>`.
|
||||
|
||||
See [USAGE.md](USAGE.md) for workspaces, backups, the search syntax and command-line usage.
|
||||
- One board per workspace, with columns, cards and colored tags.
|
||||
- Strict search expressions, for example `tag:bug OR title:login`.
|
||||
- Markdown export of the whole board, and a tag manager.
|
||||
- Multi-language interface; light, dark or system theme.
|
||||
|
||||
See [USAGE.md](USAGE.md) for installing, starting YKanBan, workspaces and backups, the search syntax and the settings file.
|
||||
|
||||
## Building
|
||||
|
||||
|
||||
@@ -1,96 +1,194 @@
|
||||
# YKanBan Usage
|
||||
|
||||
YKanBan is a local/offline kanban board. It works like Git in one respect: all data for a managed project lives in a `.ykanban` folder at the project root, so the board travels with the project folder.
|
||||
YKanBan is a local, offline kanban board. Like Git, it keeps its data in a `.ykanban` folder inside the project folder it manages (the **workspace**). Each YKanBan window manages exactly one workspace; several windows can run at the same time on different workspaces.
|
||||
|
||||
## 1. Workspace
|
||||
## Installing
|
||||
|
||||
- A **workspace** is a folder that directly contains a `.ykanban` directory. Only the given folder is checked; parent folders are never searched.
|
||||
- `.ykanban` contains `ykanban.db` (the SQLite database with the board, cards and tags) and `ykanban.lock` (the exclusive lock file).
|
||||
- A workspace is opened by exactly one YKanBan instance at a time. Opening the same workspace a second time shows the lock-conflict page.
|
||||
Each release build is a self-contained archive; no .NET runtime is needed.
|
||||
|
||||
### Command line
|
||||
| Platform | Archive | Executable |
|
||||
|---|---|---|
|
||||
| Windows x64 | `YKanBan-<version>-win-x64.zip` | `YKanBan.exe` |
|
||||
| Linux x64 | `YKanBan-<version>-linux-x64.tar.gz` | `YKanBan` |
|
||||
| macOS Apple silicon | `YKanBan-<version>-osx-arm64.tar.gz` | `YKanBan.app` (see [macOS](#macos)) |
|
||||
|
||||
Only Apple silicon macOS is a release target; there is no Intel Mac build.
|
||||
|
||||
Extract the archive anywhere. To type `ykanban <path>` as shown below, put the executable on your `PATH` under that name, for example:
|
||||
|
||||
```sh
|
||||
# Linux
|
||||
ln -s /opt/YKanBan-<version>-linux-x64/YKanBan ~/.local/bin/ykanban
|
||||
# macOS
|
||||
ln -s /Applications/YKanBan.app/Contents/MacOS/YKanBan /usr/local/bin/ykanban
|
||||
```
|
||||
|
||||
On Windows, add the extracted folder to `PATH`; `ykanban` then finds `YKanBan.exe` because Windows ignores case.
|
||||
|
||||
## Starting YKanBan
|
||||
|
||||
The only way to start YKanBan is with the workspace path:
|
||||
|
||||
```sh
|
||||
ykanban <path>
|
||||
```
|
||||
|
||||
- `<path>` is the workspace folder to open. A relative path is resolved against the current working directory.
|
||||
- Exactly one argument is required. Starting without arguments, with more than one argument, with a blank argument, with an argument starting with `-` (any option form, `--help` included), or with a path that does not exist or is not a folder shows the argument error page.
|
||||
- If the folder exists but has no `.ykanban`, the not-initialized page is shown with an **Initialize Workspace** button. Initializing creates the database and seeds the preset columns and tags in the current interface language.
|
||||
- Exactly one argument is accepted. A relative path is resolved against the current working directory, so `ykanban .` opens the current folder (but see [macOS](#macos) when starting through `open`).
|
||||
- YKanBan looks for `.ykanban` **only in `<path>` itself**; it does not search parent folders the way Git does.
|
||||
- There are no command-line options. An argument starting with `-` is never treated as a path; to open a folder whose name starts with `-`, write it as `./-name`.
|
||||
|
||||
## 2. Do not commit `.ykanban` to Git
|
||||
The path must exist and be a folder. When the board cannot be shown, the whole window shows one of these pages instead:
|
||||
|
||||
`.ykanban` holds machine-local state and a lock file; it should not be committed. Add it to your **global** gitignore so it is ignored in every repository:
|
||||
| Page | When |
|
||||
|---|---|
|
||||
| Invalid arguments | No argument, more than one argument, an empty or whitespace-only argument, an argument starting with `-` (including `--help`), a path the operating system cannot represent (for example one containing a NUL character), or a path that does not exist or is not a folder. Shows the usage line. |
|
||||
| No workspace here | `<path>` exists but has no `.ykanban`. The **Initialize workspace** button creates one, with the columns To Do / In Progress / Done and the preset tags (both named in the current interface language). |
|
||||
| Workspace locked | Another YKanBan window already has this workspace open. Close that window first. Also shown when another window takes the lock while you initialize. |
|
||||
| Cannot open workspace | `.ykanban` exists but `ykanban.db` in it is missing (restore it from a backup, or delete `.ykanban` and initialize again; YKanBan never silently creates an empty board), the database was created by a newer YKanBan, is damaged or cannot be opened, or a file-system or permission error occurred (also when initializing fails for a reason other than the lock). The English error details can be selected and copied. |
|
||||
|
||||
```
|
||||
# ~/.gitignore_global (or %USERPROFILE%\.gitignore_global on Windows)
|
||||
.ykanban/
|
||||
The window title is `<workspace name> - YKanBan` while a workspace is open and just `YKanBan` on these pages.
|
||||
|
||||
## macOS
|
||||
|
||||
The app is not notarized. After extracting, remove the download quarantine once, or macOS refuses to open it:
|
||||
|
||||
```sh
|
||||
xattr -dr com.apple.quarantine YKanBan.app
|
||||
```
|
||||
|
||||
Then enable the global ignore file once:
|
||||
Double-clicking `YKanBan.app` starts it without a path, so it only shows the **Invalid arguments** page. Start it from a terminal instead, either through Launch Services or by running the executable inside the bundle:
|
||||
|
||||
```sh
|
||||
open -n -a YKanBan --args /path/to/project
|
||||
/Applications/YKanBan.app/Contents/MacOS/YKanBan /path/to/project
|
||||
```
|
||||
|
||||
- Keep `-n`: without it, `open` only brings an already running YKanBan to the front and drops the path, instead of starting another window.
|
||||
- Give `open` an **absolute** path. An app started by `open` runs in `/`, so `open -n -a YKanBan --args .` opens `/`, not the current folder. Running the executable inside the bundle resolves relative paths normally.
|
||||
- `open -a YKanBan` finds the app once it is in `/Applications` (or another folder Launch Services knows about).
|
||||
|
||||
## Workspaces, Git and Backups
|
||||
|
||||
- **Do not commit `.ykanban` to Git.** Add it to your global ignore file once, so no repository picks it up. If `git config --global core.excludesFile` prints a file, add the line `.ykanban/` to that file; otherwise create one:
|
||||
|
||||
```sh
|
||||
echo ".ykanban/" >> ~/.gitignore_global
|
||||
git config --global core.excludesFile ~/.gitignore_global
|
||||
```
|
||||
|
||||
## 3. Backing up and migrating a workspace
|
||||
- **Back up or move all three database files together**: `ykanban.db`, `ykanban.db-wal` and `ykanban.db-shm` in `.ykanban/`. Recent changes may still be in the `-wal` file; copying only `ykanban.db` can lose them. The simplest safe backup is to close YKanBan and copy the whole `.ykanban` folder.
|
||||
- **Network shares (SMB, NFS, …) are not supported.** The database and the workspace lock rely on local file-system features that do not work reliably over a network. YKanBan does not detect this; keep workspaces on a local disk.
|
||||
- `.ykanban/ykanban.lock` is held while a window has the workspace open and is released automatically when YKanBan exits or crashes. The file itself is kept empty; only the exclusive OS handle it carries has meaning.
|
||||
|
||||
The database runs in SQLite WAL mode. A workspace is therefore **three files**, not one: `ykanban.db`, `ykanban.db-wal` and `ykanban.db-shm`.
|
||||
## Search Syntax
|
||||
|
||||
To back up or move a workspace, copy **all three files together** while YKanBan is closed. Copying only `ykanban.db` can lose the most recent changes.
|
||||
Type an expression in the search box on the **Board** tab and click **Search** (or press Enter). Searching only happens then; there is no search while typing. The **×** button clears the box and shows every card again.
|
||||
|
||||
## 4. Search syntax
|
||||
- Columns are always shown, even when none of their cards match.
|
||||
- An empty or blank expression shows every card.
|
||||
- An active search keeps the result set it produced until you search again: after adding, editing, moving or deleting cards the board shows the same matching cards as before, minus any that were deleted. Adding or editing a card does not change whether it is currently shown; press **Search** again to refresh the result.
|
||||
|
||||
The board search runs only when you press the search button (or press Enter in the search box); there is no live search. A blank query shows everything. The clear button (×) empties the box and restores the full board.
|
||||
### Examples
|
||||
|
||||
Search keywords (`AND`, `OR`) and qualifier keys are fixed English grammar and are **never localized**.
|
||||
| Expression | Finds cards… |
|
||||
|---|---|
|
||||
| `login` | whose title or content contains "login" |
|
||||
| `login crash` | containing both words (anywhere in title or content) |
|
||||
| `login OR signup` | containing either word |
|
||||
| `tag:bug title:login` | tagged `bug` whose title contains "login" |
|
||||
| `tag:bug OR tag:ui` | tagged `bug` or `ui` |
|
||||
| `(tag:bug OR tag:ui) column:Done` | tagged `bug` or `ui` in the column titled "Done" |
|
||||
| `"dark mode"` | whose title or content contains "dark mode" |
|
||||
| `tag:"needs review"` | tagged `needs review` |
|
||||
| `id:61` or `id:#61` | number 61 |
|
||||
| `"http://example.com"` | containing the URL (a `:` must be quoted) |
|
||||
| `"AND"` | containing the text "AND" |
|
||||
|
||||
### 4.1 Grammar
|
||||
### Grammar
|
||||
|
||||
```
|
||||
query := orExpr
|
||||
orExpr := andExpr ( OR andExpr )*
|
||||
andExpr := operand ( (AND)? operand )* // adjacent terms are an implicit AND
|
||||
andExpr := operand ( (AND)? operand )* -- neighbours are joined by AND
|
||||
operand := atom | '(' orExpr ')'
|
||||
atom := word | phrase | qualifier
|
||||
qualifier := key ':' (word | phrase)
|
||||
qualifier := key ':' value
|
||||
key := tag | title | content | id | column
|
||||
phrase := '"' any text '"' // escapes: \" to literal quote and \\ to literal backslash
|
||||
value := word | phrase -- tag / title / content / column
|
||||
| '#'? digit+ -- id: a positive decimal integer
|
||||
word := one or more characters, except whitespace and ( ) " : \ ;
|
||||
not equal to AND or OR
|
||||
phrase := '"' one or more characters '"' -- escapes: \" and \\
|
||||
```
|
||||
|
||||
### 4.2 Semantics
|
||||
### Operators
|
||||
|
||||
- `AND` (explicit or by adjacency) binds tighter than `OR`; parentheses force grouping.
|
||||
- Only uppercase `AND` / `OR` are operators. Lowercase `and` / `or` are plain words. To search for the literal words `AND` or `OR`, quote them, for example `"AND"`.
|
||||
- A bare word or phrase matches a **substring of the title OR the content**.
|
||||
- `tag:NAME` matches a tag by its **exact** name.
|
||||
- `column:TITLE` matches a column by its **exact** title.
|
||||
- `title:TEXT` matches a substring of the card title, and `content:TEXT` matches a substring of the card content.
|
||||
- `id:N` matches a card by its **exact** positive integer id; an optional leading `#` is allowed (`id:#61`).
|
||||
- All matching is Unicode case-insensitive (both sides are case-folded before comparing).
|
||||
- Quotes allow values with spaces, for example `tag:"release notes"` or `column:"In Progress"`.
|
||||
- Inside a phrase, `\"` produces a literal quote and `\\` a literal backslash.
|
||||
- `AND` and `OR` are operators **only in uppercase**. `and` and `or` are ordinary words.
|
||||
- Writing words next to each other means `AND`: `a b` is `a AND b`.
|
||||
- `AND` binds tighter than `OR`: `a OR b c` is `a OR (b AND c)`. Use parentheses to group differently: `(a OR b) c`.
|
||||
- To search for the literal text `AND` or `OR`, quote it: `"AND"`, `tag:"OR"`.
|
||||
- The search keywords (`AND`, `OR`, `tag`, `title`, `content`, `id`, `column`) are always English, whatever the interface language. Qualifier keys are lowercase only: `Tag:bug` is an unknown qualifier.
|
||||
|
||||
### 4.3 Strict validation
|
||||
### What Each Atom Matches
|
||||
|
||||
An invalid expression opens a modal error dialog and **does not run the search**. The error dialog is centered on the parent window; its text is a localized "query expression is invalid" message plus the parser's non-localized English detail. After closing it, the search box keeps what you typed and the board keeps the previous results.
|
||||
| Atom | Matches when |
|
||||
|---|---|
|
||||
| word or phrase | the card title **or** content contains the text |
|
||||
| `title:` value | the card title contains the text |
|
||||
| `content:` value | the card content contains the text |
|
||||
| `tag:` value | the card has a tag whose name **equals** the text |
|
||||
| `column:` value | the card is in a column whose title **equals** the text |
|
||||
| `id:` value | the card number equals the value |
|
||||
|
||||
The following are invalid:
|
||||
- A qualifier value can be a word (`tag:bug`) or a phrase (`tag:"needs review"`). Use a phrase for values containing spaces, `(`, `)`, `:` or `\`, and for the values `AND` / `OR`.
|
||||
- `id:` takes an unquoted positive integer, optionally prefixed with `#`: `id:61`, `id:#61`.
|
||||
|
||||
- unbalanced parentheses, for example `(a` or `a)`;
|
||||
- a dangling operator, for example `bug AND`;
|
||||
- consecutive operators, for example `a AND OR b`;
|
||||
- a qualifier without a value, for example `tag:`;
|
||||
- a qualifier phrase separated from its key by whitespace, for example `tag: "x"` (write `tag:"x"` instead);
|
||||
- an unterminated phrase, for example `"abc`;
|
||||
- an empty phrase, for example `""`;
|
||||
- a phrase glued to other text, for example `a"b"`;
|
||||
- an invalid escape inside a phrase (a backslash not followed by `"` or `\`), for example `tag:"a\x"`;
|
||||
- a bare backslash in a word, for example `a\b`;
|
||||
- an unquoted qualifier value containing `:` or equal to `AND`/`OR`, for example `tag:a:b` (quote the value instead);
|
||||
- an id value that is not an unquoted positive integer with an optional `#`, for example `id:0`, `id:-1` or `id:"1"`;
|
||||
- an unknown qualifier key. Only `tag`, `title`, `content`, `id` and `column` are valid, and the key is case-sensitive, so `Tag:x` is an error. A colon not preceded by a valid key (for example `:foo` or `http://x`) is an error; quote such text to search for it literally.
|
||||
### Quoting and Escapes
|
||||
|
||||
## 5. Export
|
||||
- A phrase is text in double quotes. Inside it, `\"` stands for a quote and `\\` for a backslash; any other backslash is an error.
|
||||
- Outside quotes, `\` is not allowed at all, and `:` always starts a qualifier. Quote any text containing them: `"C:\\temp"`, `"a:b"`.
|
||||
- A phrase cannot be empty, and must be separated from neighbouring words and phrases by a space or a parenthesis: write `a "b"`, not `a"b"`.
|
||||
- A qualifier's phrase value follows the `:` directly: `tag:"needs review"`, not `tag: "needs review"`.
|
||||
|
||||
The **Export** button writes a human-readable Markdown snapshot of the whole board (columns, cards and the tag table) to a file you choose. The suggested file name and the timestamps in the document follow the current interface language. The export is read-only; there is no import.
|
||||
### Case
|
||||
|
||||
All matching ignores case, for letters of every language: `tag:BUG` finds `bug`, and `ÄRGER` finds `ärger`. Text is otherwise compared literally: `%`, `_` and `*` have no special meaning.
|
||||
|
||||
Tag names and column titles must each be unique, but the uniqueness check is case-sensitive: `Bug` and `bug` are different names and can both exist. Because matching folds case, a query such as `tag:bug` then matches both.
|
||||
|
||||
### Invalid Expressions
|
||||
|
||||
An invalid expression does not search. A dialog shows "The query expression is invalid. Details: …" followed by the parser's message (always in English). After closing it, the box keeps your text for correcting and the board keeps the previous result.
|
||||
|
||||
These are invalid:
|
||||
|
||||
| Problem | Example |
|
||||
|---|---|
|
||||
| Unbalanced parentheses | `(tag:bug`, `tag:bug)` |
|
||||
| An operator with a missing side | `bug AND`, `OR bug` |
|
||||
| Consecutive operators | `a AND OR b` |
|
||||
| A qualifier without a value | `tag:` |
|
||||
| `AND` / `OR` as an unquoted qualifier value | `tag:AND` (write `tag:"AND"`) |
|
||||
| An unterminated phrase | `"dark mode` |
|
||||
| An empty phrase | `""`, `tag:""` |
|
||||
| A phrase touching other text | `a"b"`, `"a"b`, `"a""b"` |
|
||||
| A space between a qualifier and its phrase value | `tag: "needs review"` |
|
||||
| An invalid escape in a phrase | `tag:"a\x"` |
|
||||
| A backslash outside a phrase | `C:\temp` |
|
||||
| An unknown qualifier key | `label:bug`, `Tag:bug`, `http://x` |
|
||||
| An unquoted value containing `:` | `title:a:b` |
|
||||
| An `id:` value that is not an unquoted positive integer | `id:abc`, `id:0`, `id:"61"` |
|
||||
|
||||
## Settings File
|
||||
|
||||
Settings (language, theme, card sort order, column width and the confirmation switches) are stored in `app.json`:
|
||||
|
||||
| Platform | Location |
|
||||
|---|---|
|
||||
| Windows | `%APPDATA%\YKanBan\app.json` |
|
||||
| Linux, macOS | `~/.config/YKanBan/app.json` (`$XDG_CONFIG_HOME/YKanBan/app.json` when that is set) |
|
||||
|
||||
- The file is written when YKanBan exits. With several instances running, the last one to exit overwrites the file with its own settings.
|
||||
- A language change takes effect after restarting YKanBan; a theme change applies as soon as the settings dialog is accepted.
|
||||
- A missing file is normal on first run and yields the defaults. If the file exists but cannot be read (an I/O or permission error), the defaults are used.
|
||||
- If the file cannot be parsed, it is saved as `app.json.bak` and the defaults are used. This also covers an invalid enum value: an unknown theme, sort or width string, or a numeric enum value, makes the whole file fall back to defaults. A section that is simply missing falls back to its own defaults.
|
||||
Reference in new issue
Block a user