diff --git a/src/providers/bibtexformatterlib/bibtexutils.ts b/src/providers/bibtexformatterlib/bibtexutils.ts index c1e11fafc..073005d4b 100644 --- a/src/providers/bibtexformatterlib/bibtexutils.ts +++ b/src/providers/bibtexformatterlib/bibtexutils.ts @@ -88,42 +88,48 @@ export class BibtexUtils { * @param keys Array of sorting keys */ static bibtexSort(duplicates: Set, config: BibtexFormatConfig): (a: BibtexEntry, b: BibtexEntry) => number { - const keys = config.sort - return (a, b) => { - let r = 0 - for (const key of keys) { - // Select the appropriate sort function - switch (key) { - case 'key': - r = BibtexUtils.bibtexSortByKey(a, b, config) - break - case 'year-desc': - r = -BibtexUtils.bibtexSortByField('year', a, b, config) - break - case 'type': - r = BibtexUtils.bibtexSortByType(a, b, config) - break - default: - r = BibtexUtils.bibtexSortByField(key, a, b, config) - } - // Compare until different - if (r !== 0) { - break - } - } - if (r === 0 && bibtexParser.isEntry(a)) { - // It seems that items earlier in the list appear as the variable b here, rather than a - duplicates.add(a) - } - return r + return (a, b) => this.bibtexSortSwitch(a, b, duplicates, config) + } + + private static bibtexSortSwitch(a: BibtexEntry, b: BibtexEntry, duplicates: Set, config: BibtexFormatConfig): number { + const firstEntryCompare = BibtexUtils.bibtexSortFirstEntries(config.firstEntries, a, b) + if (firstEntryCompare !== 0) { + return firstEntryCompare } + const keys = config.sort + let r = 0 + for (const key of keys) { + // Select the appropriate sort function + switch (key) { + case 'key': + r = BibtexUtils.bibtexSortByKey(a, b) + break + case 'year-desc': + r = -BibtexUtils.bibtexSortByField('year', a, b, config) + break + case 'type': + r = BibtexUtils.bibtexSortByType(a, b) + break + default: + r = BibtexUtils.bibtexSortByField(key, a, b, config) + } + // Compare until different + if (r !== 0) { + break + } + } + if (r === 0 && bibtexParser.isEntry(a)) { + // It seems that items earlier in the list appear as the variable b here, rather than a + duplicates.add(a) + } + return r } /** * If one of the entries `a` or `b` is in `firstEntries` or `stickyEntries`, return an order. * Otherwise, return undefined */ - private static bibtexSortFirstEntries(firstEntries: string[], a: BibtexEntry, b: BibtexEntry): number | undefined { + private static bibtexSortFirstEntries(firstEntries: string[], a: BibtexEntry, b: BibtexEntry): number { const aFirst = firstEntries.includes(a.entryType) const bFirst = firstEntries.includes(b.entryType) if (aFirst && !bFirst) { @@ -133,13 +139,15 @@ export class BibtexUtils { } else if (aFirst && bFirst) { const aIndex = firstEntries.indexOf(a.entryType) const bIndex = firstEntries.indexOf(b.entryType) - if (aIndex <= bIndex) { + if (aIndex < bIndex) { return -1 - } else { + } else if (aIndex > bIndex) { return 1 + } else { + return 0 } } - return undefined + return 0 } /** @@ -147,11 +155,6 @@ export class BibtexUtils { * @param fieldName which field name to sort by */ private static bibtexSortByField(fieldName: string, a: BibtexEntry, b: BibtexEntry, config: BibtexFormatConfig): number { - const firstEntriesOrder = BibtexUtils.bibtexSortFirstEntries(config.firstEntries, a, b) - if (firstEntriesOrder) { - return firstEntriesOrder - } - let fieldA: string = '' let fieldB: string = '' @@ -179,8 +182,7 @@ export class BibtexUtils { return fieldA.localeCompare(fieldB) } - private static bibtexSortByKey(a: BibtexEntry, b: BibtexEntry, config: BibtexFormatConfig): number { - const firstEntriesOrder = BibtexUtils.bibtexSortFirstEntries(config.firstEntries, a, b) + private static bibtexSortByKey(a: BibtexEntry, b: BibtexEntry): number { let aKey: string | undefined = undefined let bKey: string | undefined = undefined if (bibtexParser.isEntry(a)) { @@ -189,9 +191,6 @@ export class BibtexUtils { if (bibtexParser.isEntry(b)) { bKey = b.internalKey } - if (firstEntriesOrder) { - return firstEntriesOrder - } if (!aKey && !bKey) { return 0 } else if (!aKey) { @@ -203,11 +202,7 @@ export class BibtexUtils { } } - private static bibtexSortByType(a: BibtexEntry, b: BibtexEntry, config: BibtexFormatConfig): number { - const firstEntriesOrder = BibtexUtils.bibtexSortFirstEntries(config.firstEntries, a, b) - if (firstEntriesOrder) { - return firstEntriesOrder - } + private static bibtexSortByType(a: BibtexEntry, b: BibtexEntry): number { return a.entryType.localeCompare(b.entryType) } diff --git a/test/suites/09_formatter.test.ts b/test/suites/09_formatter.test.ts index f75551072..09043477b 100644 --- a/test/suites/09_formatter.test.ts +++ b/test/suites/09_formatter.test.ts @@ -35,6 +35,9 @@ suite('Formatter test suite', () => { await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.handleDuplicates', undefined) await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.sort.enabled', undefined) await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.align-equal.enabled', undefined) + await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-entries.first', undefined) + await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-fields.sort.enabled', undefined) + await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-fields.order', undefined) if (path.basename(fixture) === 'testground') { rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}}) @@ -165,7 +168,7 @@ suite('Formatter test suite', () => { assert.notStrictEqual(lines[5].trim().slice(-1), ',') }) - test.run(suiteName, fixtureName, 'test bibtex sort with `bibtex-format.sortby`', async () => { + test.run(suiteName, fixtureName, 'test bibtex sorter with `bibtex-format.sortby`', async () => { await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}]) await test.open(fixture, 'main.bib') @@ -210,7 +213,7 @@ suite('Formatter test suite', () => { assert.ok(entries[2].includes('MR1241645')) }) - test.run(suiteName, fixtureName, 'test bibtex formatter with `bibtex-format.handleDuplicates`', async () => { + test.run(suiteName, fixtureName, 'test bibtex sorter with `bibtex-format.handleDuplicates`', async () => { await test.load(fixture, [{src: 'formatter/bibtex_dup.bib', dst: 'main.bib'}]) await test.open(fixture, 'main.bib') @@ -254,7 +257,7 @@ suite('Formatter test suite', () => { assert.ok(entries[0].includes('MR1241645')) }) - test.only(suiteName, fixtureName, 'test bibtex formatter with `bibtex-format.align-equal.enabled`', async () => { + test.run(suiteName, fixtureName, 'test bibtex formatter with `bibtex-format.align-equal.enabled`', async () => { await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}]) await test.open(fixture, 'main.bib') @@ -273,4 +276,49 @@ suite('Formatter test suite', () => { assert.ok(lines) assert.ok(allEqual(lines.filter(line => line.includes('=')).map(line => line.indexOf('=')))) }) + + test.run(suiteName, fixtureName, 'test bibtex sorter with `bibtex-entries.first`', async () => { + await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}]) + await test.open(fixture, 'main.bib') + + await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-entries.first', ['book']) + await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.sortby', ['key']) + await vscode.commands.executeCommand('latex-workshop.bibsort') + await test.sleep(1000) + const lines = vscode.window.activeTextEditor?.document.getText().split('\n') + assert.ok(lines) + const entries = lines.filter(line => line.includes('@')) + assert.ok(entries[2].includes('art1')) + assert.ok(entries[0].includes('lamport1994latex')) + assert.ok(entries[1].includes('MR1241645')) + }) + + test.run(suiteName, fixtureName, 'test bibtex aligner with `bibtex-fields.sort.enabled` and `bibtex-fields.order`', async () => { + await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}]) + await test.open(fixture, 'main.bib') + + await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-fields.sort.enabled', true) + await vscode.commands.executeCommand('latex-workshop.bibalign') + await test.sleep(1000) + let lines = vscode.window.activeTextEditor?.document.getText().split('\n') + assert.ok(lines) + let entries = lines.filter(line => line.includes('=')) + assert.ok(entries[0].includes('author')) + assert.ok(entries[1].includes('description')) + assert.ok(entries[2].includes('journal')) + assert.ok(entries[3].includes('title')) + assert.ok(entries[4].includes('year')) + + await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-fields.order', ['title', 'author', 'year']) + await vscode.commands.executeCommand('latex-workshop.bibalign') + await test.sleep(1000) + lines = vscode.window.activeTextEditor?.document.getText().split('\n') + assert.ok(lines) + entries = lines.filter(line => line.includes('=')) + assert.ok(entries[0].includes('title')) + assert.ok(entries[1].includes('author')) + assert.ok(entries[2].includes('year')) + assert.ok(entries[3].includes('description')) + assert.ok(entries[4].includes('journal')) + }) })