<commit_before>'use babel'

import {CompositeDisposable}	from 'atom'
import ElasticTabstopsBuilder	from './ElasticTabstopsBuilder'
import {queryAll, prepend, after, replaceWith}	from './dom'

const LINE	= 'div.line'
const TAB	= 'span.hard-tab:not(.trailing-whitespace)'

const LEADING	= 'leading-whitespace'
const INVISIBLE	= 'invisible-character'


const subscriptions = new CompositeDisposable()
export function activate(state) {
	// console.log('activate', state)
	subscriptions.add(
		atom.workspace.observeTextEditors(observeEditor)
	)
}
export function deactivate() {
	// console.log('deactivate')
	subscriptions.dispose()

	for (const editor of atom.workspace.getTextEditors()) {
		const editorElement = atom.views.getView(editor)
		editorElement.classList.remove('elastic-tabstops')

		// unpatch lines component
		const c = editorElement.component.linesComponent
		if (c._updateTileNodes) c.updateTileNodes = c._updateTileNodes
	}
}

function observeEditor(editor) {
	// console.log('observe editor')

	const editorElement = atom.views.getView(editor)
	editorElement.classList.add('elastic-tabstops')

	// monkey patch lines component
	const c = editorElement.component.linesComponent
	c._updateTileNodes = c.updateTileNodes
	c.updateTileNodes =	function () {
			this._updateTileNodes()
			if (editor.getSoftTabs()) return
			update(this.getDomNode())
		}

	const handles = new Set
	function update(containerElement) {
		if (handles.size > 0) {
			// console.log('cancle old alignments', handles.size)
			for (const handle of handles) cancelAnimationFrame(handle)
			handles.clear()
		}

		// console.time('create column blocks')
		const tabstops = createTabstops(containerElement)
		// console.timeEnd('create column blocks')

		const cursorBlocks = new Set
		for (const position of editor.getCursorScreenPositions()) {
			const blocks = tabstops.getColumnBlocksOfLine(position.row)
			if (blocks) for (const block of blocks) cursorBlocks.add(block)
		}
		const lines = new Set
		for (const block of cursorBlocks) {
			for (let i = 0; i < block.cells.length; ++i) lines.add(block.line + i)
		}

		const presenter = editorElement.component.presenter
		const y = presenter.getLinesYardstick()
		const cache = y.leftPixelPositionCache
			|| y.pixelPositionsByLineIdAndColumn // Atom < 1.9
		for (const line of lines) {
			const id = presenter.lineIdForScreenRow(line)
			delete cache[id]
		}

		// console.time('align blocks at cursors')
		// for (const block of tabstops.columnBlocks) align(block.cells)
		for (const block of cursorBlocks) {
			align(block.cells)
		}
		// console.timeEnd('align blocks at cursors')<commit_msg>seems do not need clear cache in recent atom versions.<commit_after>'use babel'

import {CompositeDisposable}	from 'atom'
import ElasticTabstopsBuilder	from './ElasticTabstopsBuilder'
import {queryAll, prepend, after, replaceWith}	from './dom'

const LINE	= 'div.line'
const TAB	= 'span.hard-tab:not(.trailing-whitespace)'

const LEADING	= 'leading-whitespace'
const INVISIBLE	= 'invisible-character'


const subscriptions = new CompositeDisposable()
export function activate(state) {
	// console.log('activate', state)
	subscriptions.add(
		atom.workspace.observeTextEditors(observeEditor)
	)
}
export function deactivate() {
	// console.log('deactivate')
	subscriptions.dispose()

	for (const editor of atom.workspace.getTextEditors()) {
		const editorElement = atom.views.getView(editor)
		editorElement.classList.remove('elastic-tabstops')

		// unpatch lines component
		const c = editorElement.component.linesComponent
		if (c._updateTileNodes) c.updateTileNodes = c._updateTileNodes
	}
}

function observeEditor(editor) {
	// console.log('observe editor')

	const editorElement = atom.views.getView(editor)
	editorElement.classList.add('elastic-tabstops')

	// monkey patch lines component
	const c = editorElement.component.linesComponent
	c._updateTileNodes = c.updateTileNodes
	c.updateTileNodes =	function () {
			this._updateTileNodes()
			if (editor.getSoftTabs()) return
			update(this.getDomNode())
		}

	// function clearCache(lines) {
	// 	const presenter = editorElement.component.presenter
	// 	const y = presenter.getLinesYardstick()
	// 	if (lines) for (const line of lines) {
	// 		const cache = y.leftPixelPositionCache
	// 			|| y.pixelPositionsByLineIdAndColumn // Atom < 1.9
	// 		const id = presenter.lineIdForScreenRow(line)
	// 		delete cache[id]
	// 	} else {
	// 		y.leftPixelPositionCache = {}
	// 	}
	// }

	// clearCache()

	const handles = new Set
	function update(containerElement) {
		if (handles.size > 0) {
			// console.log('cancle old alignments', handles.size)
			for (const handle of handles) cancelAnimationFrame(handle)
			handles.clear()
		}

		// console.time('create column blocks')
		const tabstops = createTabstops(containerElement)
		// console.timeEnd('create column blocks')

		const cursorBlocks = new Set
		for (const position of editor.getCursorScreenPositions()) {
			const blocks = tabstops.getColumnBlocksOfLine(position.row)
			if (blocks) for (const block of blocks) cursorBlocks.add(block)
		}
		const lines = new Set
		for (const block of cursorBlocks) {
			for (let i = 0; i < block.cells.length; ++i) lines.add(block.line + i)
		}

		// console.time('align blocks at cursors')
		// for (const block of tabstops.columnBlocks) align(block.cells)
		for (const block of cursorBlocks) {
			align(block.cells)
		}
		// console.timeEnd('align blocks at cursors')
{'fraction_non_alphanumeric': 0.11677360219981668, 'fraction_numerical': 0.001466544454628781, 'mean_word_length': 4.312560856864654, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1424382', 'n_tokens_mistral': 1872, 'n_tokens_neox': 1716, 'n_words': 409}