Files
Loki/frontend/node_modules/micromark/lib/initialize/document.js
T
MichaelandClaude Opus 5 b405adea6c Jauge de contexte, espace disque sur partage agrégé, panneau Fichiers
Trois défauts sans rapport entre eux, tous visibles à l'écran.

Jauge de contexte bloquée à « 0 / N (0 %) » : le comptage exact vient de
usage.prompt_tokens (include_usage), qu'un llama-server récent a cessé de
renvoyer. On note désormais si l'usage est arrivé ; sinon la fin de tour
publie l'estimation qui pilote déjà la compaction — approximative, mais
jamais absente. Et la souscription envoie la valeur courante juste après
le rattrapage : une page rechargée affichait zéro sur une discussion
pourtant pleine, faute d'événement ctx_used dans la fenêtre rejouée.

Espace disque : « il ne reste que 11,9 Go » sur un partage Unraid qui en
a des centaines. /mnt/user est servi par shfs, un FUSE qui agrège
plusieurs disques — statfs y renvoie l'espace d'un seul, et ce chiffre
REFUSAIT l'installation du modèle. Les systèmes de fichiers qui
approximent (FUSE, overlay, NFS, CIFS, Ceph, Gluster) sont reconnus par
leur magie : leur chiffre reste affiché, précédé d'un « ~ », mais ne
bloque plus rien.

Panneau Fichiers : le panneau entier défilait, emportant vers le haut
l'en-tête, le fil d'Ariane et le pied (occupation disque, bouton .zip)
dès qu'il y avait quelques fichiers. Seule la liste défile maintenant ;
le pied reste en bas et l'état vide se centre.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 08:28:53 +02:00

362 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @import {
* Construct,
* ContainerState,
* InitialConstruct,
* Initializer,
* Point,
* State,
* TokenizeContext,
* Tokenizer,
* Token
* } from 'micromark-util-types'
*/
/**
* @typedef {[Construct, ContainerState]} StackItem
* Construct and its state.
*/
import { factorySpace } from 'micromark-factory-space';
import { markdownLineEnding } from 'micromark-util-character';
import { splice } from 'micromark-util-chunked';
/** @type {InitialConstruct} */
export const document = {
tokenize: initializeDocument
};
/** @type {Construct} */
const containerConstruct = {
tokenize: tokenizeContainer
};
/**
* @this {TokenizeContext}
* Self.
* @type {Initializer}
* Initializer.
*/
function initializeDocument(effects) {
const self = this;
/** @type {Array<StackItem>} */
const stack = [];
let continued = 0;
/** @type {TokenizeContext | undefined} */
let childFlow;
/** @type {Token | undefined} */
let childToken;
/** @type {number} */
let lineStartOffset;
return start;
/** @type {State} */
function start(code) {
// First we iterate through the open blocks, starting with the root
// document, and descending through last children down to the last open
// block.
// Each block imposes a condition that the line must satisfy if the block is
// to remain open.
// For example, a block quote requires a `>` character.
// A paragraph requires a non-blank line.
// In this phase we may match all or just some of the open blocks.
// But we cannot close unmatched blocks yet, because we may have a lazy
// continuation line.
if (continued < stack.length) {
const item = stack[continued];
self.containerState = item[1];
return effects.attempt(item[0].continuation, documentContinue, checkNewContainers)(code);
}
// Done.
return checkNewContainers(code);
}
/** @type {State} */
function documentContinue(code) {
continued++;
// Note: this field is called `_closeFlow` but it also closes containers.
// Perhaps a good idea to rename it but it’s already used in the wild by
// extensions.
if (self.containerState._closeFlow) {
self.containerState._closeFlow = undefined;
if (childFlow) {
closeFlow();
}
// Note: this algorithm for moving events around is similar to the
// algorithm when dealing with lazy lines in `writeToChild`.
const indexBeforeExits = self.events.length;
let indexBeforeFlow = indexBeforeExits;
/** @type {Point | undefined} */
let point;
// Find the flow chunk.
while (indexBeforeFlow--) {
if (self.events[indexBeforeFlow][0] === 'exit' && self.events[indexBeforeFlow][1].type === "chunkFlow") {
point = self.events[indexBeforeFlow][1].end;
break;
}
}
exitContainers(continued);
// Fix positions.
let index = indexBeforeExits;
while (index < self.events.length) {
self.events[index][1].end = {
...point
};
index++;
}
// Inject the exits earlier (they’re still also at the end).
splice(self.events, indexBeforeFlow + 1, 0, self.events.slice(indexBeforeExits));
// Discard the duplicate exits.
self.events.length = index;
return checkNewContainers(code);
}
return start(code);
}
/** @type {State} */
function checkNewContainers(code) {
// Next, after consuming the continuation markers for existing blocks, we
// look for new block starts (e.g. `>` for a block quote).
// If we encounter a new block start, we close any blocks unmatched in
// step 1 before creating the new block as a child of the last matched
// block.
if (continued === stack.length) {
// No need to `check` whether there’s a container, of `exitContainers`
// would be moot.
// We can instead immediately `attempt` to parse one.
if (!childFlow) {
return documentContinued(code);
}
// If we have concrete content, such as block HTML or fenced code,
// we can’t have containers “pierce” into them, so we can immediately
// start.
if (childFlow.currentConstruct && childFlow.currentConstruct.concrete) {
return flowStart(code);
}
// If we do have flow, it could still be a blank line,
// but we’d be interrupting it w/ a new container if there’s a current
// construct.
// To do: next major: remove `_gfmTableDynamicInterruptHack` (no longer
// needed in micromark-extension-gfm-table@1.0.6).
self.interrupt = Boolean(childFlow.currentConstruct && !childFlow._gfmTableDynamicInterruptHack);
}
// Check if there is a new container.
self.containerState = {};
return effects.check(containerConstruct, thereIsANewContainer, thereIsNoNewContainer)(code);
}
/** @type {State} */
function thereIsANewContainer(code) {
if (childFlow) closeFlow();
exitContainers(continued);
return documentContinued(code);
}
/** @type {State} */
function thereIsNoNewContainer(code) {
self.parser.lazy[self.now().line] = continued !== stack.length;
lineStartOffset = self.now().offset;
return flowStart(code);
}
/** @type {State} */
function documentContinued(code) {
// Try new containers.
self.containerState = {};
return effects.attempt(containerConstruct, containerContinue, flowStart)(code);
}
/** @type {State} */
function containerContinue(code) {
continued++;
stack.push([self.currentConstruct, self.containerState]);
// Try another.
return documentContinued(code);
}
/** @type {State} */
function flowStart(code) {
if (code === null) {
if (childFlow) closeFlow();
exitContainers(0);
effects.consume(code);
return;
}
childFlow = childFlow || self.parser.flow(self.now());
effects.enter("chunkFlow", {
_tokenizer: childFlow,
contentType: "flow",
previous: childToken
});
return flowContinue(code);
}
/** @type {State} */
function flowContinue(code) {
if (code === null) {
writeToChild(effects.exit("chunkFlow"), true);
exitContainers(0);
effects.consume(code);
return;
}
if (markdownLineEnding(code)) {
effects.consume(code);
writeToChild(effects.exit("chunkFlow"));
// Get ready for the next line.
continued = 0;
self.interrupt = undefined;
return start;
}
effects.consume(code);
return flowContinue;
}
/**
* @param {Token} token
* Token.
* @param {boolean | undefined} [endOfFile]
* Whether the token is at the end of the file (default: `false`).
* @returns {undefined}
* Nothing.
*/
function writeToChild(token, endOfFile) {
const stream = self.sliceStream(token);
if (endOfFile) stream.push(null);
token.previous = childToken;
if (childToken) childToken.next = token;
childToken = token;
childFlow.defineSkip(token.start);
childFlow.write(stream);
// Alright, so we just added a lazy line:
//
// ```markdown
// > a
// b.
//
// Or:
//
// > ~~~c
// d
//
// Or:
//
// > | e |
// f
// ```
//
// The construct in the second example (fenced code) does not accept lazy
// lines, so it marked itself as done at the end of its first line, and
// then the content construct parses `d`.
// Most constructs in markdown match on the first line: if the first line
// forms a construct, a non-lazy line can’t “unmake” it.
//
// The construct in the third example is potentially a GFM table, and
// those are *weird*.
// It *could* be a table, from the first line, if the following line
// matches a condition.
// In this case, that second line is lazy, which “unmakes” the first line
// and turns the whole into one content block.
//
// We’ve now parsed the non-lazy and the lazy line, and can figure out
// whether the lazy line started a new flow block.
// If it did, we exit the current containers between the two flow blocks.
if (self.parser.lazy[token.start.line]) {
let index = childFlow.events.length;
while (index--) {
if (
// The token starts before the line ending…
childFlow.events[index][1].start.offset < lineStartOffset && (
// …and either is not ended yet…
!childFlow.events[index][1].end ||
// …or ends after it.
childFlow.events[index][1].end.offset > lineStartOffset)) {
// Exit: there’s still something open, which means it’s a lazy line
// part of something.
return;
}
}
// Note: this algorithm for moving events around is similar to the
// algorithm when closing flow in `documentContinue`.
const indexBeforeExits = self.events.length;
let indexBeforeFlow = indexBeforeExits;
/** @type {boolean | undefined} */
let seen;
/** @type {Point | undefined} */
let point;
// Find the previous chunk (the one before the lazy line).
while (indexBeforeFlow--) {
if (self.events[indexBeforeFlow][0] === 'exit' && self.events[indexBeforeFlow][1].type === "chunkFlow") {
if (seen) {
point = self.events[indexBeforeFlow][1].end;
break;
}
seen = true;
}
}
exitContainers(continued);
// Fix positions.
index = indexBeforeExits;
while (index < self.events.length) {
self.events[index][1].end = {
...point
};
index++;
}
// Inject the exits earlier (they’re still also at the end).
splice(self.events, indexBeforeFlow + 1, 0, self.events.slice(indexBeforeExits));
// Discard the duplicate exits.
self.events.length = index;
}
}
/**
* @param {number} size
* Size.
* @returns {undefined}
* Nothing.
*/
function exitContainers(size) {
let index = stack.length;
// Exit open containers.
while (index-- > size) {
const entry = stack[index];
self.containerState = entry[1];
entry[0].exit.call(self, effects);
}
stack.length = size;
}
function closeFlow() {
childFlow.write([null]);
childToken = undefined;
childFlow = undefined;
self.containerState._closeFlow = undefined;
}
}
/**
* @this {TokenizeContext}
* Context.
* @type {Tokenizer}
* Tokenizer.
*/
function tokenizeContainer(effects, ok, nok) {
// Always populated by defaults.
return factorySpace(effects, effects.attempt(this.parser.constructs.document, ok, nok), "linePrefix", this.parser.constructs.disable.null.includes('codeIndented') ? undefined : 4);
}