Skip to content

Commit 81d72b8

Browse files
committed
Support @string in bibtex structure pane
1 parent 7362b68 commit 81d72b8

File tree

2 files changed

+61
-45
lines changed

2 files changed

+61
-45
lines changed

src/providers/completer/citation.ts

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,54 @@ function readCitationFormat(configuration: vscode.WorkspaceConfiguration, exclud
7777
return fields
7878
}
7979

80+
export const bibTools = {
81+
expandField,
82+
deParenthesis,
83+
parseAbbrevations
84+
}
85+
86+
function expandField(abbreviations: {[key: string]: string}, value: bibtexParser.FieldValue): string {
87+
if (value.kind === 'concat') {
88+
const args = value.content as bibtexParser.FieldValue[]
89+
return args.map(arg => expandField(abbreviations, arg)).join(' ')
90+
}
91+
if (bibtexParser.isAbbreviationValue(value)) {
92+
if (value.content in abbreviations) {
93+
return abbreviations[value.content]
94+
}
95+
return ''
96+
}
97+
return value.content
98+
}
99+
100+
function deParenthesis(str: string): string {
101+
// Remove wrapping { }
102+
// Extract the content of \url{}
103+
return str.replace(/\\url{([^\\{}]+)}/g, '$1').replace(/{+([^\\{}]+)}+/g, '$1')
104+
}
105+
106+
function parseAbbrevations(ast: bibtexParser.BibtexAst) {
107+
const abbreviations: {[key: string]: string} = {}
108+
ast.content.filter(bibtexParser.isStringEntry).forEach((entry: bibtexParser.StringEntry) => {
109+
// @string{string1 = "Proceedings of the "}
110+
// @string{string2 = string1 # "Foo"}
111+
if (typeof entry.value.content === 'string') {
112+
abbreviations[entry.abbreviation] = entry.value.content
113+
} else {
114+
abbreviations[entry.abbreviation] =
115+
(entry.value.content as (bibtexParser.AbbreviationValue | bibtexParser.TextStringValue)[]).map(subEntry => {
116+
if (bibtexParser.isAbbreviationValue(subEntry)) {
117+
return abbreviations[subEntry.content] ?? `undefined @string "${subEntry.content}"`
118+
} else {
119+
return subEntry.content
120+
}
121+
}).join('')
122+
}
123+
})
124+
125+
return abbreviations
126+
}
127+
80128
export class Citation implements IProvider {
81129
/**
82130
* Bib entries in each bib `file`.
@@ -261,23 +309,7 @@ export class Citation implements IProvider {
261309
lw.eventBus.fire(eventbus.FileParsed, fileName)
262310
return
263311
}
264-
const abbreviations: {[key: string]: string} = {}
265-
ast.content.filter(bibtexParser.isStringEntry).forEach((entry: bibtexParser.StringEntry) => {
266-
// @string{string1 = "Proceedings of the "}
267-
// @string{string2 = string1 # "Foo"}
268-
if (typeof entry.value.content === 'string') {
269-
abbreviations[entry.abbreviation] = entry.value.content
270-
} else {
271-
abbreviations[entry.abbreviation] =
272-
(entry.value.content as (bibtexParser.AbbreviationValue | bibtexParser.TextStringValue)[]).map(subEntry => {
273-
if (bibtexParser.isAbbreviationValue(subEntry)) {
274-
return abbreviations[subEntry.content] ?? `undefined @string "${subEntry.content}"`
275-
} else {
276-
return subEntry.content
277-
}
278-
}).join('')
279-
}
280-
})
312+
const abbreviations = parseAbbrevations(ast)
281313
ast.content
282314
.filter(bibtexParser.isEntry)
283315
.forEach((entry: bibtexParser.Entry) => {
@@ -293,7 +325,7 @@ export class Citation implements IProvider {
293325
fields: new Fields()
294326
}
295327
entry.content.forEach(field => {
296-
const value = this.deParenthesis(this.expandField(abbreviations, field.value))
328+
const value = deParenthesis(expandField(abbreviations, field.value))
297329
item.fields.set(field.name, value)
298330
})
299331
newEntry.push(item)
@@ -304,20 +336,6 @@ export class Citation implements IProvider {
304336
lw.eventBus.fire(eventbus.FileParsed, fileName)
305337
}
306338

307-
private expandField(abbreviations: {[key: string]: string}, value: bibtexParser.FieldValue): string {
308-
if (value.kind === 'concat') {
309-
const args = value.content as bibtexParser.FieldValue[]
310-
return args.map(arg => this.expandField(abbreviations, arg)).join(' ')
311-
}
312-
if (bibtexParser.isAbbreviationValue(value)) {
313-
if (value.content in abbreviations) {
314-
return abbreviations[value.content]
315-
}
316-
return ''
317-
}
318-
return value.content
319-
}
320-
321339
removeEntriesInFile(file: string) {
322340
logger.log(`Remove parsed bib entries for ${file}`)
323341
this.bibEntries.delete(file)
@@ -360,10 +378,4 @@ export class Citation implements IProvider {
360378
}
361379
return items
362380
}
363-
364-
private deParenthesis(str: string): string {
365-
// Remove wrapping { }
366-
// Extract the content of \url{}
367-
return str.replace(/\\url{([^\\{}]+)}/g, '$1').replace(/{+([^\\{}]+)}+/g, '$1')
368-
}
369381
}

src/providers/structurelib/bibtex.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@ import { TeXElement, TeXElementType } from '../structure'
44
import { parser } from '../../components/parser'
55

66
import { getLogger } from '../../components/logger'
7+
import { bibTools } from '../completer/citation'
78

89
const logger = getLogger('Structure', 'BibTeX')
910

1011
/**
1112
* Convert a bibtexParser.FieldValue to a string
1213
* @param field the bibtexParser.FieldValue to parse
1314
*/
14-
function fieldValueToString(field: bibtexParser.FieldValue): string {
15-
if (field.kind === 'concat') {
16-
return field.content.map(value => fieldValueToString(value)).reduce((acc, cur) => {return acc + ' # ' + cur})
17-
} else {
18-
return field.content
19-
}
15+
function fieldValueToString(field: bibtexParser.FieldValue, abbreviations: {[abbr: string]: string}): string {
16+
if (field.kind === 'concat') {
17+
return field.content.map(value => fieldValueToString(value, abbreviations)).reduce((acc, cur) => {return acc + ' # ' + cur})
18+
} else if (field.kind === 'abbreviation') {
19+
return abbreviations[field.content] ?? `undefined @string "${field.content}"`
20+
} else {
21+
return field.content
22+
}
2023
}
2124

2225
export async function buildBibTeX(document: vscode.TextDocument): Promise<TeXElement[]> {
@@ -31,6 +34,7 @@ export async function buildBibTeX(document: vscode.TextDocument): Promise<TeXEle
3134
return []
3235
}
3336
logger.log(`Parsed ${ast.content.length} AST items.`)
37+
const abbreviations = bibTools.parseAbbrevations(ast)
3438
const ds: TeXElement[] = []
3539
ast.content.filter(bibtexParser.isEntry)
3640
.forEach(entry => {
@@ -44,7 +48,7 @@ export async function buildBibTeX(document: vscode.TextDocument): Promise<TeXEle
4448
children: []
4549
}
4650
entry.content.forEach(field => {
47-
const content = fieldValueToString(field.value)
51+
const content = fieldValueToString(field.value, abbreviations)
4852
const fielditem: TeXElement = {
4953
type: TeXElementType.BibField,
5054
name: field.name,

0 commit comments

Comments
 (0)