diff options
| author | Dax <[email protected]> | 2025-09-15 03:28:08 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-09-15 03:28:08 -0400 |
| commit | 725104572e2b6d64dcfc145d4748124186427c7b (patch) | |
| tree | daf5b26437fd267bc41848e0578ed13d1b43bb52 /packages/app/src/utils/dom.ts | |
| parent | 4954edf8aeb5b8b395fc4f4e91b7fe36cfab212d (diff) | |
| download | opencode-725104572e2b6d64dcfc145d4748124186427c7b.tar.gz opencode-725104572e2b6d64dcfc145d4748124186427c7b.zip | |
feat: add desktop/web app package (#2606)
Co-authored-by: adamdotdevin <[email protected]>
Co-authored-by: Adam <[email protected]>
Co-authored-by: GitHub Action <[email protected]>
Diffstat (limited to 'packages/app/src/utils/dom.ts')
| -rw-r--r-- | packages/app/src/utils/dom.ts | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/packages/app/src/utils/dom.ts b/packages/app/src/utils/dom.ts new file mode 100644 index 000000000..4f3724c7c --- /dev/null +++ b/packages/app/src/utils/dom.ts @@ -0,0 +1,51 @@ +export function getCharacterOffsetInLine(lineElement: Element, targetNode: Node, offset: number): number { + const r = document.createRange() + r.selectNodeContents(lineElement) + r.setEnd(targetNode, offset) + return r.toString().length +} + +export function getNodeOffsetInLine(lineElement: Element, charIndex: number): { node: Node; offset: number } | null { + const walker = document.createTreeWalker(lineElement, NodeFilter.SHOW_TEXT, null) + let remaining = Math.max(0, charIndex) + let lastText: Node | null = null + let lastLen = 0 + let node: Node | null + while ((node = walker.nextNode())) { + const len = node.textContent?.length || 0 + lastText = node + lastLen = len + if (remaining <= len) return { node, offset: remaining } + remaining -= len + } + if (lastText) return { node: lastText, offset: lastLen } + if (lineElement.firstChild) return { node: lineElement.firstChild, offset: 0 } + return null +} + +export function getSelectionInContainer( + container: HTMLElement, +): { sl: number; sch: number; el: number; ech: number } | null { + const s = window.getSelection() + if (!s || s.rangeCount === 0) return null + const r = s.getRangeAt(0) + const sc = r.startContainer + const ec = r.endContainer + const getLineElement = (n: Node) => + (n.nodeType === Node.TEXT_NODE ? (n.parentElement as Element) : (n as Element))?.closest(".line") + const sle = getLineElement(sc) + const ele = getLineElement(ec) + if (!sle || !ele) return null + if (!container.contains(sle as Node) || !container.contains(ele as Node)) return null + const cc = container.querySelector("code") as HTMLElement | null + if (!cc) return null + const lines = Array.from(cc.querySelectorAll(".line")) + const sli = lines.indexOf(sle as Element) + const eli = lines.indexOf(ele as Element) + if (sli === -1 || eli === -1) return null + const sl = sli + 1 + const el = eli + 1 + const sch = getCharacterOffsetInLine(sle as Element, sc, r.startOffset) + const ech = getCharacterOffsetInLine(ele as Element, ec, r.endOffset) + return { sl, sch, el, ech } +} |
