Skip to content
This repository has been archived by the owner on Feb 20, 2024. It is now read-only.

Commit

Permalink
bug: fix arnog#504 "Spacing is inconsistent after editing"
Browse files Browse the repository at this point in the history
  • Loading branch information
arnog committed Jun 24, 2020
1 parent 5194684 commit 9278259
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 57 deletions.
2 changes: 1 addition & 1 deletion dist/mathlive.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/mathlive.mjs

Large diffs are not rendered by default.

28 changes: 0 additions & 28 deletions src/core/atom-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,31 +158,11 @@ export function decompose(
}
console.assert(!result || isArray(result));
} else {
let previousType = 'none';
let nextType = atoms[1].type;
let selection: Span[] = [];
let digitOrTextStringID = '';
let lastWasDigit = true;
let phantomBase = null;
for (let i = 0; i < atoms.length; i++) {
// Is this a binary operator ('+', '-', etc...) that potentially
// needs to be adjusted to a unary operator?
//
// When preceded by a mbin, mopen, mrel, mpunct, mop or
// when followed by a mrel, mclose or mpunct
// or if preceded or followed by no sibling, a 'mbin' becomes a
// 'mord'
if (atoms[i].type === 'mbin') {
if (
/first|none|mrel|mpunct|mopen|mbin|mop/.test(
previousType
) ||
/none|mrel|mpunct|mclose/.test(nextType)
) {
atoms[i].type = 'mord';
}
}

// If this is a scaffolding supsub, we'll use the
// phantomBase from the previous atom to position the supsub.
// Otherwise, no need for the phantomBase
Expand Down Expand Up @@ -247,14 +227,6 @@ export function decompose(
result = result.concat(flat);
}
}

// Since the next atom (and this atom!) could have children
// use getFinal...() and getInitial...() to get the closest
// atom linearly.
previousType = atoms[i].getFinalBaseElement().type;
nextType = atoms[i + 1]
? atoms[i + 1].getInitialBaseElement().type
: 'none';
}

// Is there a leftover selection?
Expand Down
58 changes: 37 additions & 21 deletions src/core/span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,40 +363,38 @@ export class Span {
* of the span. Implemented as a Unicode character if possible, a margin-left otherwise.
* This is used to adjust the inter-spacing between spans of different types,
* e.g. 'bin' and 'rel', according to the TeX rules (TexBook p.170)
*
* @param hscale - If a value is provided, the margins are scaled by
* this factor.
*
* @return HTML markup
*/

toMarkup(hskip = 1.0, hscale = 1.0): string {
let result = '';
let body = this.body || '';

//
// 1. Calculate the spacing between atoms, based on their type
// (`mord`, `mbin`, `mrel`, etc...)
//
if (this.children) {
let previousType = 'none';
for (const child of this.children) {
for (let i = 0; i < this.children.length; i++) {
const child = this.children[i];
let spacing = 0;
if (previousType) {
let type = child.type;
if (type) {
if (type === 'textord') type = 'mord';
if (type === 'first') type = 'none';
if (child.isTight) {
spacing =
INTER_ATOM_TIGHT_SPACING[
previousType + '+' + type
] || 0;
} else {
spacing =
INTER_ATOM_SPACING[previousType + '+' + type] ||
0;
}
spacing = Math.floor(hscale * spacing);
}
const type = getEffectiveType(this.children, i);
const combinedType = previousType + '+' + type;
if (child.isTight) {
spacing = INTER_ATOM_TIGHT_SPACING[combinedType] ?? 0;
} else {
spacing = INTER_ATOM_SPACING[combinedType] ?? 0;
}
body += child.toMarkup(spacing, hscale);
previousType = lastSpanType(child);
previousType = type;
}
}

// Collapse 'empty' spans
if (
(body === '\u200b' || (!body && !this.svgBody)) &&
Expand Down Expand Up @@ -625,10 +623,28 @@ export class Span {
}
}

function lastSpanType(span: Span): string {
const result = span.type;
function getEffectiveType(xs: Span[], i: number): string {
if (i < 0 || i >= xs.length) return 'none';

const prevType = xs[i - 1]?.type ?? 'none';
const nextType = xs[i + 1]?.type ?? 'none';

let result = xs[i].type ?? 'none';

if (result === 'first') return 'none';
if (result === 'textord') return 'mord';
if (result === 'mbin') {
// If a `mbin` span, i.e. "+" is after or before spans
// of a certain type, consider it to be a `mord` instead.
// This is to handle proper spacing of, e.g. "-4" vs "1-4"
if (
/first|none|mrel|mpunct|mopen|mbin|mop/.test(prevType) ||
/none|mrel|mpunct|mclose/.test(nextType)
) {
result = 'mord';
}
}

return result;
}

Expand Down
12 changes: 6 additions & 6 deletions test/math.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,14 @@ describe('BINARY OPERATORS', function () {
hasType('a+b', '+', 'mbin');
hasType('f(a)+f(b)', '+', 'mbin');
hasType('x^n+y^n', '+', 'mbin');
hasType('+b', '+', 'mord');
hasType('(+b', '+', 'mord');
hasType('=+b', '+', 'mord');
hasType('\\sin+b', '+', 'mord');
hasType(', +b', '+', 'mord');
hasType('+b', '+', 'mbin');
hasType('(+b', '+', 'mbin');
hasType('=+b', '+', 'mbin');
hasType('\\sin+b', '+', 'mbin');
hasType(', +b', '+', 'mbin');

hasType('\\textcolor{red}{a}+b', '+', 'mbin');
hasType('\\textcolor{red}{a=}+b', '+', 'mord');
hasType('\\textcolor{red}{a=}+b', '+', 'mbin');

hasType('a^2+b', '+', 'mbin');
hasType('a^{2}+b', '+', 'mbin');
Expand Down

0 comments on commit 9278259

Please sign in to comment.