import * as CF from '@efforting.tech/data/field-configuration-factories'; export const Indention_Mode = new CF.symbol_set({ AUTO: 'Automatic detection of indention mode', SPACES: 'Indention is based on spaces', TABULATORS: 'Indention is based on tabulators', }, 'Indention mode'); // BUG: Current implementation of CF.symbol_set doesn't support default value export const Text_Settings = new CF.Schema({ indention_mode: Indention_Mode, indention_tabulator_width: CF.cardinal_value(4, 'Width of a tabulator in spaces'), first_line: CF.natural_value(1, 'First line number'), }, 'Text settings'); export function string_has_contents(str) { return /\S/.test(str); } export function *indented_line_iterator(settings, text) { let line_no = settings.first_line; let index = 0; const { indention_tabulator_width } = settings; switch (settings.indention_mode) { case Indention_Mode.symbols.TABULATORS: { for (const line of text.matchAll(/^(\t*)(.*)$/gm)) { const [raw, tabs, remaining] = line; yield { raw, indent: tabs.length, line: remaining, line_no: line_no++, index: index++}; } break; } case Indention_Mode.symbols.SPACES: { for (const line of text.matchAll(/^([ ]*)(.*)$/gm)) { const [raw, spaces, remaining] = line; if ((spaces.length % indention_tabulator_width) !== 0) { throw new Error('Unaligned indention'); //TODO - proper error } yield { raw, indent: Math.floor(spaces.length / indention_tabulator_width), line: remaining, line_no: line_no++, index: index++}; } break; } default: throw new Error(`Unsupported indention mode: ${settings.indention_mode}`); //TODO - proper error } }