# Concealing syntax

**URL:** https://discuss.codemirror.net/t/concealing-syntax/3135
**Category:** v6
**Created:** [April 24, 2021, 2:48pm UTC](https://discuss.codemirror.net/t/concealing-syntax/3135 "2021-04-24T14:48:31Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![sillyp](https://discuss.codemirror.net/letter_avatar_proxy/v4/letter/s/f17d59/32.png) [@sillyp](https://discuss.codemirror.net/u/sillyp)
#### Post date: [April 24, 2021, 2:48pm UTC](https://discuss.codemirror.net/t/concealing-syntax/3135/1 "2021-04-24T14:48:31Z")

</div>

Hey,  
Is it possible to hide some parts of the syntax when a line is not in focus?  
For example:

- display the string ‘lambda’ as ‘λ’ or
- “!=” as “≠”

This is similar to [Vim’s conceal feature.](https://www.youtube.com/watch?v=37rIbrdHKwM)

I have had some luck doing this with replace widgets with but I am not able to remove the decoration when the line is in focus. Also, it _feels_ like I’m not approaching it correct.

Any guidance will be greatly appreciated 🙏

Thank you so much

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/marijn/32/136_2.png) [@marijn](https://discuss.codemirror.net/u/marijn)
#### Post date: [April 24, 2021, 3:26pm UTC](https://discuss.codemirror.net/t/concealing-syntax/3135/2 "2021-04-24T15:26:42Z")

</div>

Replacing widget decorations would be the way to go for this, yes. Make sure you skip the line with the selection head in it, and update (probably a full rebuild of the widgets inside the viewport is fine) when the selection, document, or viewport changes.

---

<div class="post-metadata">

### Author: ![sillyp](https://discuss.codemirror.net/letter_avatar_proxy/v4/letter/s/f17d59/32.png) [@sillyp](https://discuss.codemirror.net/u/sillyp)
#### Post date: [April 25, 2021, 9:57am UTC](https://discuss.codemirror.net/t/concealing-syntax/3135/3 "2021-04-25T09:57:49Z")

</div>

Thank you so much it worked! 😄

Instead of skipping the complete line, I am skipping any range that overlaps with the selection range.

For anybody who finds this post, this is how I implemented the feature

```javascript
class ConcealWidget extends WidgetType {

    constructor(readonly symbol: string) {
        super()
    }

    eq(other: ConcealWidget) {
        return (other.symbol == this.symbol)
    }

    toDOM() {
        let span = document.createElement("span")
        span.className = "cm-concealed-sym" /* Formatting to be taken care of*/
        span.textContent = this.symbol
        return span;
    }

    ignoreEvent() {
        return false
    }
}

function selectionAndRangeOverlap(selection: EditorSelection, rangeFrom:
    number, rangeTo: number) {
    return (selection.main.from <= rangeTo) &&
        (selection.main.to) >= rangeFrom;
}

function conceal(view: EditorView) {

    const concealMap = {
        "!=": "≠",
        "<=": "≤",
        ">=": "≥",
        // and so on...
    }

    let widgets: any = []
    for (let { from, to } of view.visibleRanges) {
        syntaxTree(view.state).iterate({
            from, to, enter: (type, from, to) => {
                const toSkip: Boolean = selectionAndRangeOverlap(
                    view.state.selection, from, to)
                    if (
                        (type.name == "CompareOp" || type.name = "LogicOp") 
                        && !toSkip
                    ) {
                        const s: string = view.state.doc.sliceString(from, to)
                        if ( !concealMap.hasOwnProperty(s) ) {
                            return
                        }
                        widgets.push(Decoration.replace({
                            widget: new ConcealWidget(),
                            inclusive: false,
                            block: false,
                        }).range(from, to))
                    }
            }
        })
    }
    return Decoration.set(widgets, true)
}

export const concealPlugin = ViewPlugin.fromClass(class {
    decorations: DecorationSet
    constructor(view: EditorView) {
        this.decorations = conceal(view)
    }
    update(update: ViewUpdate) {
        if (update.docChanged || update.viewportChanged || update.selectionSet)
            this.decorations = conceal(update.view)
    }
}, { decorations: v => v.decorations, })

```

Will check if the code has any issues but looks good so far

---

<div class="post-metadata">

### Author: ![qbane](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/qbane/32/703_2.png) [@qbane](https://discuss.codemirror.net/u/qbane)
#### Post date: [April 25, 2021, 4:18pm UTC](https://discuss.codemirror.net/t/concealing-syntax/3135/4 "2021-04-25T16:18:04Z")

</div>

Nice work. A small typo, in `concealPlugin`, `images` should be `conceal` instead.

---

<div class="post-metadata">

### Author: ![sillyp](https://discuss.codemirror.net/letter_avatar_proxy/v4/letter/s/f17d59/32.png) [@sillyp](https://discuss.codemirror.net/u/sillyp)
#### Post date: [April 25, 2021, 4:40pm UTC](https://discuss.codemirror.net/t/concealing-syntax/3135/5 "2021-04-25T16:40:41Z")

</div>

Thanks for the catch! I have updated the post
