Skip to content

Commit

Permalink
Fixed #463, improving preferred spacing.
Browse files Browse the repository at this point in the history
  • Loading branch information
amyjko committed May 14, 2024
1 parent 181e81a commit ccfa278
Show file tree
Hide file tree
Showing 31 changed files with 289 additions and 381 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Dates are in `YYYY-MM-DD` format and versions are in [semantic versioning](http:
- Reset stage output when locales change.
- Signficantly reduced memory usage of edit history
- Improved preferred spacing of compound data structures and blocks.
- Faster and more correct and stable preferred spacing algorithm.

## 0.9.4 2024-05-04

Expand Down
8 changes: 7 additions & 1 deletion src/basis/Basis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ function checkBasisNodes(node: Node) {

expect(
unparsables,
unparsables.map((unp) => unp.toWordplay()).join(),
'Unparsable at: `' +
node.toWordplay().substring(0, 30) +
'...' +
unparsables
.map((unp) => unp.unparsables.map((t) => t.toWordplay()).join())
.join() +
'`',
).toHaveLength(0);

// Check for conflicts, ignoring unused binds.
Expand Down
6 changes: 3 additions & 3 deletions src/components/concepts/CodeView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import type Type from '../../nodes/Type';
import Spaces from '../../parser/Spaces';
import ConceptLinkUI from './ConceptLinkUI.svelte';
import getPreferredSpaces from '@parser/getPreferredSpaces';
export let node: Node;
export let concept: Concept | undefined = undefined;
Expand All @@ -30,7 +31,7 @@
function copy() {
// Copy node needs a source to manage spacing, so we make one.
copyNode(node, Spaces.withPreferredSpace(node));
copyNode(node, getPreferredSpaces(node));
}
</script>

Expand All @@ -46,8 +47,7 @@
on:keydown={(event) =>
event.key === 'c' && (event.ctrlKey || event.metaKey)
? copy()
: undefined}
><RootView {node} {inline} {spaces} preferred={true} /></div
: undefined}><RootView {node} {inline} {spaces} /></div
>{#if type && concept}&nbsp;<TypeView
{type}
context={concept.context}
Expand Down
1 change: 0 additions & 1 deletion src/components/concepts/ExampleUI.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@
.example {
display: flex;
flex-direction: column;
gap: var(--wordplay-spacing);
}
.code.inline {
Expand Down
5 changes: 1 addition & 4 deletions src/components/editor/Editor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -1451,10 +1451,7 @@
<!-- Show the node's label and type -->
{$caret.position.getLabel(
$locales,
)}{#if caretExpressionType}&nbsp;{TYPE_SYMBOL}&nbsp;{caretExpressionType.toWordplay(
undefined,
$locales.getLocale(),
)}{/if}
)}{#if caretExpressionType}&nbsp;{TYPE_SYMBOL}&nbsp;{caretExpressionType.toWordplay()}{/if}
<PlaceholderView position={$caret.position} />{/if}</div
>
{/key}
Expand Down
13 changes: 9 additions & 4 deletions src/components/editor/NodeView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
getEvaluation,
getHidden,
getInsertionPoint,
getRoot,
getSpace,
} from '../project/Contexts';
import getNodeView from './util/nodeToView';
Expand All @@ -21,6 +22,7 @@
export let small = false;
const evaluation = getEvaluation();
const root = getRoot();
$: description =
node && $evaluation
Expand Down Expand Up @@ -54,7 +56,9 @@
// Get the root's computed spaces store
let spaces = getSpace();
// See if this node has any space to render.
$: space = node && $spaces ? $spaces.get(node) : undefined;
$: firstToken = node?.getFirstLeaf();
$: spaceRoot = $root && node ? $root.getSpaceRoot(node) : undefined;
$: space = spaceRoot && $spaces ? $spaces.getSpace(spaceRoot) : '';
// Get the hidden context.
let hidden = getHidden();
Expand All @@ -70,9 +74,10 @@
<!-- Don't render anything if we weren't given a node. -->
{#if node !== undefined}
<!-- Render space preceding this node, if any, then either a value view if stepping or the node. -->
{#if space && !hide}<Space
{...space}
insertion={$insertion?.token === space.token
{#if !hide && firstToken && spaceRoot === node}<Space
token={firstToken}
{space}
insertion={$insertion?.token === firstToken
? $insertion
: undefined}
/>{/if}<div
Expand Down
12 changes: 1 addition & 11 deletions src/components/editor/Space.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
export let token: Token;
export let space: string;
export let additional: string;
export let insertion: InsertionPoint | undefined = undefined;
$: insertionIndex =
Expand All @@ -28,11 +27,6 @@
$spaceIndicator,
);
$: additionalSpaces =
additional.length === 0
? []
: render(additional, false, $spaceIndicator);
function render(
text: string,
explicit: boolean,
Expand Down Expand Up @@ -68,11 +62,7 @@
>{#each afterSpaces as s, index}{#if index > 0}<span
><br class="break" /></span
>{/if}<span data-uiid="space-text">{s}</span
>{/each}{#each additionalSpaces as s, index}{#if index > 0}<span
><br class="break" /></span
>{/if}{#if s === ''}&ZeroWidthSpace;{:else}<span
data-uiid="space-text">{s}</span
>{/if}{/each}</span
>{/each}</span
></span
>
{/key}
Expand Down
13 changes: 6 additions & 7 deletions src/components/editor/util/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import type Project from '../../../models/Project';
import interpret from './interpret';
import { TileKind } from '../../project/Tile';
import { TAB_SYMBOL } from '@parser/Spaces';
import getPreferredSpaces from '@parser/getPreferredSpaces';

export type Command = {
/** The iconographic text symbol to use */
Expand Down Expand Up @@ -1188,9 +1189,7 @@ const Commands: Command[] = [
if (!(context.caret?.position instanceof Node)) return false;
copyNode(
context.caret.position,
context.caret.source.spaces.withPreferredSpace(
context.caret.source,
),
getPreferredSpaces(context.caret.source),
);
return context.caret.delete(context.project, false) ?? true;
},
Expand All @@ -1210,9 +1209,7 @@ const Commands: Command[] = [
return (
copyNode(
context.caret.position,
context.caret.source.spaces.withPreferredSpace(
context.caret.source,
),
getPreferredSpaces(context.caret.source),
) ?? false
);
},
Expand Down Expand Up @@ -1300,7 +1297,9 @@ const Commands: Command[] = [
if (caret) {
const length = caret.source.code.getLength();
const position = caret.getTextPosition(true) ?? 0;
const tidySource = caret.source.withPreferredSpace();
const tidySource = caret.source.withSpaces(
getPreferredSpaces(caret.source.root, caret.source.spaces),
);
return [
tidySource,
caret
Expand Down
10 changes: 5 additions & 5 deletions src/components/editor/util/interpret.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import getPreferredSpaces from '@parser/getPreferredSpaces';
import TableLiteral from '../../../nodes/TableLiteral';
import Spaces from '../../../parser/Spaces';

/** See if this is a kind of text we can convert into something Wordplay formatted. */
export default function interpret(text: string): string {
// Does it seem like CSV data? Convert it to a table.
if (
/^(('|“|"|”)?[a-zA-Z0-9.%&-() ]*('|"|“|”)?(,|\n|\\Z)\s*){5,}/g.test(
text.trim()
text.trim(),
)
) {
const data = parseCSV(text.trim());

const table = TableLiteral.from(data);
if (table) return table.toWordplay(Spaces.withPreferredSpace(table));
if (table) return table.toWordplay(getPreferredSpaces(table));
}

return text;
Expand All @@ -32,7 +32,7 @@ function parseCSV(data: string, fieldSep = ',', newLine = '\n'): string[][] {
'\\n])"([^"]*(?:""[^"]*)*)"(?=($|[' +
fieldSep +
'\\n]))',
'g'
'g',
);
return data
.replace(/\r/g, '')
Expand All @@ -51,7 +51,7 @@ function parseCSV(data: string, fieldSep = ',', newLine = '\n'): string[][] {
cell
.replace(nSepRe, newLine)
.replace(qSepRe, '"')
.replace(cSepRe, ',')
.replace(cSepRe, ','),
);
});
}
16 changes: 7 additions & 9 deletions src/components/project/Contexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import type { InsertionPoint } from '../../edit/Drag';
import type Caret from '../../edit/Caret';
import type Project from '@models/Project';
import type Node from '@nodes/Node';
import type Token from '@nodes/Token';
import type { Highlights } from '../editor/util/Highlights';
import type Evaluate from '@nodes/Evaluate';
import type Step from '@runtime/Step';
Expand All @@ -25,6 +24,7 @@ import type {
} from '../editor/util/Commands';
import type { CaretPosition } from '../../edit/Caret';
import type LanguageCode from '../../locale/LanguageCode';
import type Spaces from '@parser/Spaces';

// App related contexts

Expand Down Expand Up @@ -70,7 +70,7 @@ export type KeyModifierState = {
export const KeyModfifierSymbol = Symbol('modifiers');
export function getKeyboardModifiers() {
return getContext<Writable<KeyModifierState> | undefined>(
KeyModfifierSymbol
KeyModfifierSymbol,
);
}

Expand Down Expand Up @@ -118,7 +118,7 @@ export function getCaret() {
export type EditHandler = (
edit: Edit | ProjectRevision | undefined,
idle: IdleKind,
focus: boolean
focus: boolean,
) => void;

/** Various components outside the editor use this to apply edits */
Expand Down Expand Up @@ -173,9 +173,7 @@ export function getHighlights() {
}

export const SpaceSymbol = Symbol('space');
export type SpaceContext = Writable<
Map<Node, { token: Token; space: string; additional: string }>
>;
export type SpaceContext = Writable<Spaces>;
export function getSpace() {
return getContext<SpaceContext>(SpaceSymbol);
}
Expand Down Expand Up @@ -230,7 +228,7 @@ export function getSelectedOutputPaths():
export function setSelectedOutput(
paths: SelectedOutputPathsContext,
project: Project,
evaluates: Evaluate[]
evaluates: Evaluate[],
) {
// Map each selected output to its replacement, then set the selected output to the replacements.
paths.set(
Expand All @@ -239,7 +237,7 @@ export function setSelectedOutput(
source: project.getSourceOf(output),
path: project.getRoot(output)?.getPath(output),
};
})
}),
);
}

Expand Down Expand Up @@ -268,7 +266,7 @@ export const AnnouncerSymbol = Symbol('announcer');
export type Announce = (
id: string,
language: LanguageCode | undefined,
message: string
message: string,
) => void;
export function getAnnounce(): Readable<Announce | undefined> {
return getContext(AnnouncerSymbol);
Expand Down
38 changes: 5 additions & 33 deletions src/components/project/RootView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import Docs from '@nodes/Docs';
import Names from '@nodes/Names';
import type Node from '@nodes/Node';
import type Token from '@nodes/Token';
import Spaces from '@parser/Spaces';
import NodeView from '@components/editor/NodeView.svelte';
import {
Expand All @@ -25,12 +24,11 @@
import TextLiteral from '../../nodes/TextLiteral';
import FormattedLiteral from '../../nodes/FormattedLiteral';
import type Caret from '@edit/Caret';
import getPreferredSpaces from '@parser/getPreferredSpaces';
export let node: Node;
/** Optional space. To enable preferred space, set flag below. */
export let spaces: Spaces | undefined = undefined;
/** If on, and no space is provided, preferred space is rendered. */
export let preferred = false;
export let inert = false;
export let inline = false;
/** If inline, and true, this will be a maximum width */
Expand All @@ -48,40 +46,14 @@
setContext(RootSymbol, rootStore);
// When the spaces change, update the rendered spaces
let renderedSpace: SpaceContext = writable(new Map());
let renderedSpace: SpaceContext = writable(
spaces ?? getPreferredSpaces(node),
);
setContext(SpaceSymbol, renderedSpace);
$: renderedSpace.set(spaces ?? getPreferredSpaces(node));
$: if (inert) setContext(CaretSymbol, undefined);
$: {
// Reset the space.
const newSpace = new Map();
// Compute the space for every node
for (const n of node.nodes()) {
// Get the first leaf of this node.
const firstLeaf = n.getFirstLeaf() as Token | undefined;
if (firstLeaf === undefined) continue;
// Determine if the first leaf is the leaf's space root.
if (root.getSpaceRoot(firstLeaf) !== n) continue;
// What's the given space?
let space = spaces ? spaces.getSpace(firstLeaf) : '';
let additional =
spaces === undefined && preferred
? Spaces.getPreferredPrecedingSpace(
root,
space,
firstLeaf,
false,
)
: '';
newSpace.set(n, { token: firstLeaf, space, additional });
}
renderedSpace.set(newSpace);
}
// A set of hidden nodes, such as hidden translations.
let hidden = writable<Set<Node>>(new Set());
setContext(HiddenSymbol, hidden);
Expand Down
Loading

0 comments on commit ccfa278

Please sign in to comment.