From 3ec2c8027e4f8c6988cc1dc6a9dc381c91fdea88 Mon Sep 17 00:00:00 2001 From: Mariusz Kaczmarczyk Date: Fri, 16 Oct 2020 21:03:57 +0200 Subject: [PATCH] Jumble text --- readme.md | 1 + src/excmds.ts | 19 ++++++++++++++++++- src/lib/config.ts | 2 ++ src/lib/editor.ts | 7 +++++++ src/lib/editor_utils.ts | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 26238c55..9236ad23 100644 --- a/readme.md +++ b/readme.md @@ -104,6 +104,7 @@ You can try `:help key` to know more about `key`. If it is an existing binding, - `zi`/`zo`/`zz` — zoom in/out/reset zoom - ``/`` — jump to the next/previous part of the page - `g?` — Apply Caesar cipher to page (run `g?` again to switch back) +- `g!` — Jumble words on page #### Find mode diff --git a/src/excmds.ts b/src/excmds.ts index 60ac46ea..f3398ab6 100644 --- a/src/excmds.ts +++ b/src/excmds.ts @@ -129,7 +129,7 @@ import * as DOM from "@src/lib/dom" import * as CommandLineContent from "@src/content/commandline_content" import * as scrolling from "@src/content/scrolling" import { ownTab } from "@src/lib/webext" -import { wrap_input, getLineAndColNumber, rot13_helper } from "@src/lib/editor_utils" +import { wrap_input, getLineAndColNumber, rot13_helper, jumble_helper } from "@src/lib/editor_utils" import * as finding from "@src/content/finding" import * as toys from "./content/toys" import * as hinting from "@src/content/hinting" @@ -4363,6 +4363,23 @@ export function rot13(n: number) { body.currentNode.textContent = rot13_helper(t, n) } } +/** + * Perform text jumbling (reibadailty). + * + * Shuffles letters except for first and last in all words in text nodes in the current tab. Only characters in + * the ASCII range are considered. + * + * Inspired by: https://www.newscientist.com/letter/mg16221887-600-reibadailty/ + */ +//#content +export function jumble() { + const body = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, { acceptNode: node => NodeFilter.FILTER_ACCEPT }) + + while (body.nextNode()) { + const t = body.currentNode.textContent + body.currentNode.textContent = jumble_helper(t) + } +} /** * Hacky ex string parser. * diff --git a/src/lib/config.ts b/src/lib/config.ts index 383c0c3f..58d1cbbc 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -239,6 +239,7 @@ export class default_config { x: "stop", gi: "focusinput -l", "g?": "rot13", + "g!": "jumble", "g;": "changelistjump -1", J: "tabprev", K: "tabnext", @@ -603,6 +604,7 @@ export class default_config { prefremove: "removepref", tabclosealltoright: "tabcloseallto right", tabclosealltoleft: "tabcloseallto left", + reibadailty: "jumble", } /** diff --git a/src/lib/editor.ts b/src/lib/editor.ts index a3248235..ce895a17 100644 --- a/src/lib/editor.ts +++ b/src/lib/editor.ts @@ -25,6 +25,7 @@ import { getWordBoundaries, wordAfterPos, rot13_helper, + jumble_helper } from "@src/lib/editor_utils" /** @@ -403,3 +404,9 @@ export const rot13 = wrap_input((text, selectionStart, selectionEnd) => [ selectionStart, null, ]) + +export const jumble = wrap_input((text, selectionStart, selectionEnd) => [ + jumble_helper(text.slice(0, selectionStart) + text.slice(selectionEnd)), + selectionStart, + null, +]) diff --git a/src/lib/editor_utils.ts b/src/lib/editor_utils.ts index e37215f2..661bec14 100644 --- a/src/lib/editor_utils.ts +++ b/src/lib/editor_utils.ts @@ -292,3 +292,40 @@ export const charesar = (c: string, n = 13): string => { return String.fromCharCode(((cn - 97 + n) % 26) + 97) return c } + +/** @hidden + * Shuffles only letters except for the first and last letter in a word, where "word" + * is a sequence of one of: only lowercase letters OR 5 or more uppercase letters OR an uppercase letter followed + * by only lowercase letters. + */ +export const jumble_helper = (text: string): string => { + const wordSplitRegex = new RegExp("([^a-zA-Z]|[A-Z][a-z]+)") + return text.split(wordSplitRegex).map(jumbleWord).join("") +} + +function jumbleWord(word: string): string { + if (word.length < 4 || isAcronym()) { + return word + } + const innerText = word.slice(1, -1) + return word.charAt(0) + shuffle(innerText) + word.charAt(word.length - 1) + + function isAcronym() { + return word.length < 5 && word.toUpperCase() === word + } +} + +/** + * Shuffles input string + * @param text string to be shuffled + */ +export const shuffle = (text: string): string => { + const arr = text.split("") + for (let i = arr.length - 1; i >= 0; i--) { + const j = Math.floor(Math.random() * i + 1) + const t = arr[i] + arr[i] = arr[j] + arr[j] = t + } + return arr.join("") +}