* Build decorations for indent guides
( view: EditorView, config: Required<IndentGuidesConfig>, lineCache: IndentLineCache, styleCache: GuideStyleCache, )
| 158 | * Build decorations for indent guides |
| 159 | */ |
| 160 | function buildDecorations( |
| 161 | view: EditorView, |
| 162 | config: Required<IndentGuidesConfig>, |
| 163 | lineCache: IndentLineCache, |
| 164 | styleCache: GuideStyleCache, |
| 165 | ): DecorationSet { |
| 166 | const builder = new RangeSetBuilder<Decoration>(); |
| 167 | const { state } = view; |
| 168 | const tabSize = getTabSize(state); |
| 169 | const indentUnit = getIndentUnitColumns(state); |
| 170 | const guideStepPx = Math.max(view.defaultCharacterWidth * indentUnit, 1); |
| 171 | let processedLines = 0; |
| 172 | |
| 173 | for (const { from: blockFrom, to: blockTo } of view.visibleRanges) { |
| 174 | const startLine = state.doc.lineAt(blockFrom); |
| 175 | const endLine = state.doc.lineAt(blockTo); |
| 176 | const firstLineNumber = startLine.number; |
| 177 | const lastLineNumber = endLine.number; |
| 178 | const scanStartLine = Math.max(1, firstLineNumber - BLANK_LINE_SCAN_LIMIT); |
| 179 | const scanEndLine = Math.min( |
| 180 | state.doc.lines, |
| 181 | lastLineNumber + BLANK_LINE_SCAN_LIMIT, |
| 182 | ); |
| 183 | const prevIndentByLine = new Map<number, number>(); |
| 184 | const nextIndentByLine = new Map<number, number>(); |
| 185 | let prevIndent = -1; |
| 186 | let prevIndentLine = -1; |
| 187 | |
| 188 | for (let lineNum = scanStartLine; lineNum <= scanEndLine; lineNum++) { |
| 189 | const line = state.doc.line(lineNum); |
| 190 | const info = getCachedLineInfo(lineNum, line.text, tabSize, lineCache); |
| 191 | prevIndentByLine.set( |
| 192 | lineNum, |
| 193 | lineNum - prevIndentLine <= BLANK_LINE_SCAN_LIMIT ? prevIndent : -1, |
| 194 | ); |
| 195 | if (!info.blank) { |
| 196 | prevIndent = info.indentColumns; |
| 197 | prevIndentLine = lineNum; |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | let nextIndent = -1; |
| 202 | let nextIndentLine = state.doc.lines + 1; |
| 203 | for (let lineNum = scanEndLine; lineNum >= scanStartLine; lineNum--) { |
| 204 | const line = state.doc.line(lineNum); |
| 205 | const info = getCachedLineInfo(lineNum, line.text, tabSize, lineCache); |
| 206 | nextIndentByLine.set( |
| 207 | lineNum, |
| 208 | nextIndentLine - lineNum <= BLANK_LINE_SCAN_LIMIT ? nextIndent : -1, |
| 209 | ); |
| 210 | if (!info.blank) { |
| 211 | nextIndent = info.indentColumns; |
| 212 | nextIndentLine = lineNum; |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | for (let lineNum = firstLineNumber; lineNum <= lastLineNumber; lineNum++) { |
| 217 | if (processedLines >= MAX_VISIBLE_GUIDE_LINES) return builder.finish(); |
no test coverage detected