Use this page to understand the log: how revision rows are rendered, how point and relation navigation work, and how to copy structured fields. The separate Files, Diffs, and Operations page continues from a selected revision into diffs, blobs, annotations, Ediff, process output, and Jujutsu's operation log.
Log Buffer
The log buffer is the heart of Majutsu. It displays the history graph using a
custom template DSL that mirrors the jj log output but adds interactivity.
Log Display
Each revision in the log is a section. The visible anchor line is built from
fields assigned to the heading module plus any auxiliary fields assigned to
the tail module in majutsu-log-commit-columns (for example, author and
timestamp). Graph prefixes and graph-related indentation are rendered as
display-only prefix decoration rather than real buffer text, so they do not get
copied accidentally and point does not land on them as editable text. When a
revision has body module content (for example, continuation lines from a long
description), that content forms the foldable section body; its current
visibility follows the section state instead of being forced closed on every
refresh.
Press [ to jump to a visible parent and ] to jump to a visible child. When
more than one target is visible, completion returns the canonical revision id
while displaying its description as an annotation.
Log Options Transient
- Key: l (Vanilla) (majutsu-log-transient)
Open the log options transient.
- Key: L (Evil) (majutsu-log-transient)
Open the log options transient.
Useful transient entries include:
- Key: -r
Set a revset filter with Majutsu's standard revset expression reader (e.g.,
all(),mine(), orA | B). The current filter is prefilled for editing; submit an empty value to clear it.- Key: -n
Limit the number of revisions shown.
- Key: -v
Toggle reverse order.
- Key: -G
Toggle the ASCII graph.
- Key: --
Add fileset/path filters to limit the log to matching files.
- Key: W
Save the current log arguments as defaults for this jj repository.
Revision Selection
Majutsu's transient selection system chooses revision / change values; it is not a general revset builder. For repeatable arguments, an active log region adds each selected commit. Otherwise, when point is in a semantic revision section, the section's value is used. Only outside such a section does the toggle fall back to literal revision syntax under point and then the surrounding buffer context.
For arguments that accept a single value, only one selected revision is used.
Majutsu does not convert a region into an expression such as A..B or
synthesize revset operators and functions. Enter such expressions directly
with the normal revset reader, for example, the log transient's -r entry.
When no explicit value is selected, each command applies its own documented
fallback.
Log Output Protocol (Sequential Markers)
Majutsu's log parser uses an ordered marker protocol embedded in jj template output:
Entry start:
\x1dSTail start:
\x1dTBody start:
\x1dBMetadata start:
\x1dMEntry end:
\x1dE
Within each module payload, fields are separated by \x1e.
Protocol control bytes are reserved:
\x1dfor module markers\x1efor field boundaries\x1ffor encoded logical newlines
Avoid emitting these bytes literally in user templates unless intentionally participating in the protocol.
Newline rules:
heading module: may contain real physical newlines.
tail/body/metadata modules: stay in the trailing payload; encode logical newlines as
\x1fand decode them in postprocessing.
Parsing is strictly sequential and positional (not key/value based):
Detect
\x1dSand lock the entry indent column.Collect heading lines until
\x1dTis found.Parse
T -> B -> M -> Epayload segments in order on the final heading line (no extra physical line breaks between these module markers).Keep lines between current entry
Eand next entrySattached to the current section heading area (graph continuation lines).
majutsu-log-commit-columns
majutsu-log-commit-columns is a flat list of column plists. Each plist
declares one field occurrence in one row module.
:fieldRequired field symbol.
:moduleRequired; one of
heading,tail,body, ormetadata.:templateRequired Majutsu template form, or a bound template variable.
:faceOptional highlighting policy; defaults to
t.:postOptional postprocessor function, function list,
:default, ornil.
A field may occur in different modules, but the same field/module pair may
occur only once. :instance is reserved for compiler-generated occurrence
ids.
Only metadata occurrences populate canonical entry fields. The default
columns therefore include metadata occurrences for id, commit-id,
parent-ids, flags, and description. Preserve the fields needed by
stable section identity, relation navigation and annotations, and hash copying
when replacing the entire column list.
Module Semantics
headingVisible anchor-line content on the left (can span physical lines before the tail segment begins).
tailSingle-line auxiliary content rendered on the anchor line with right alignment. It remains searchable as real text, but copying a mixed heading+tail region drops the tail text by default; copying the tail alone preserves it.
bodyFoldable section body.
metadataParsed/stored for behavior and lookup; not directly shown by default.
Row Metadata
Rendered row spans are tagged with majutsu-row-module,
majutsu-row-field, majutsu-row-column, majutsu-row-entry-id, and
majutsu-row-decoration so explicit copy commands can distinguish content
from graph/tail decorations.
Hidden transport fields exist only when declared as metadata columns. The
default list includes canonical metadata for identity, navigation,
annotations, and copying; replacing the whole list also replaces those
guarantees.
Face Policy (:face)
tPreserve jj-provided text properties/highlighting.
nilStrip text properties (plain string).
FACE-SYMBOLRepaint field using that face.
If :face is omitted, Majutsu preserves jj-provided text properties (t).
Postprocessing (:post)
:post can be:
A function symbol
A list of functions (applied left-to-right)
Omitted or
:default(uses default postprocessors)nil(disable column postprocessors)
Function contract:
(fn VALUE &optional CTX) => NEW-VALUE
CTX includes at least :field, :module, and the normalized :column
spec.
Postprocessors run per column instance, so the same field can appear in
multiple modules and project to different values. Transport decoding (for
example, turning \x1f back into \n) happens before :post runs.
When you provide a function or function list in :post, Majutsu appends it
after the field's default postprocessors.
Configuration Examples
Minimal columns
(setopt majutsu-log-commit-columns
'((:field change-id :module heading
:template majutsu-log-template-change-id :face t)
(:field description :module heading
:template majutsu-log-template-description :face t)
(:field author :module tail
:template majutsu-log-template-author :face magit-log-author)
(:field timestamp :module tail
:template majutsu-log-template-timestamp :face magit-log-date)
(:field long-desc :module body
:template majutsu-log-template-long-desc :face t)
(:field id :module metadata
:template majutsu-log-template-id :face nil)
(:field commit-id :module metadata
:template [:commit_id] :face nil)
(:field parent-ids :module metadata
:template majutsu-log-template-parent-ids :face nil)
(:field flags :module metadata
:template majutsu-log-template-flags :face nil)
(:field description :module metadata
:template [:description :first_line] :face nil)))
Keep heading multiline + encoded body multiline
;; heading field can emit real newlines directly
(setopt majutsu-log-template-description
[:concat [:change_id] "\n" [:description]])
;; non-heading field should encode line breaks as \x1f
(setopt majutsu-log-template-long-desc
[:description :lines :skip 1 :join "\x1f"])
Custom postprocessor
(defun my-log-trim (value &optional _ctx)
(if (stringp value) (string-trim-right value) value))
(setopt majutsu-log-commit-columns
(mapcar
(lambda (column)
(if (and (eq (plist-get column :field) 'description)
(eq (plist-get column :module) 'heading))
(plist-put (copy-sequence column) :post #'my-log-trim)
column))
majutsu-log-commit-columns))
Copying From Structured Row Buffers
majutsu-log-mode, majutsu-evolog-mode, and majutsu-op-log-mode share
these copy commands through majutsu-row-copy-transient.
- Key: ? w s (majutsu-copy-section-value)
Copy the current section value. An active region uses ordinary region copy.
- Key: ? w f (majutsu-row-copy-field)
Copy the rendered field value at point.
- Key: ? w F (majutsu-row-copy-entry-field)
Choose any canonical field stored on the current entry, including hidden metadata that is not visible in the current layout. Completion keeps the field name as the candidate and displays a one-line value preview as its annotation.
- Key: ? w m (majutsu-row-copy-module)
Copy the rendered visible module at point (
heading,tail, orbody), without graph-prefix or tail-spacer decoration.
This keeps ordinary Emacs copying predictable while still offering precise row-aware copy operations when you want semantic rather than purely visual text.