Skip to content

Commit

Permalink
Remove thunderbird support
Browse files Browse the repository at this point in the history
Mozilla isn't interested in enabling Firenvim to work in Thunderbird
again ( glacambre#1263 ). The code
supporting Thunderbird in Firenvim makes things more complicated than
they should be, so removing it will enable a refactor that will make
Firenvim easier to work with.

Closes glacambre#1185 .
  • Loading branch information
glacambre committed Nov 2, 2022
1 parent ace9cc3 commit b59c95e
Show file tree
Hide file tree
Showing 12 changed files with 20 additions and 333 deletions.
17 changes: 6 additions & 11 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 29,7 @@ npm run build
npm run install_manifests
```

These commands should create four directories: `target/chrome`, `target/firefox`, `target/thunderbird` and `target/xpi`.
These commands should create three directories: `target/chrome`, `target/firefox` and `target/xpi`.

## Installing the addon

Expand All @@ -45,19 45,14 @@ To install Firenvim in regular mode, go to `about:addons`, click on the cog icon

To install Firenvim in dev mode, go to `about:debugging`, click "Load Temporary Add-On" and select `target/firefox/manifest.json`.

### Thunderbird

In Thunderbird, click the "hamburger menu" (the three horizontal bars) at the top right corner of the screen. Select "Addons", this should open the Add-ons Manager. Once there, click on the cog icon. If you want to install Firenvim in regular mode, select "Install Add-On From File" and choose `target/xpi/thunderbird-latest.xpi`. To install Firenvim in dev mode, select "Debug Add-On", then "Load Temporary Add-On" and choose `target/thunderbird/manifest.json`.

## Working on Firenvim

`npm run build` is slow and performs lots of checks. In order to iterate faster, you can use `"$(npm bin)/webpack --env=firefox"` or `"$(npm bin)/webpack" --env=chrome` or `"$(npm bin)/webpack" --env=thunderbird` to build only for the target you care about. Make sure you click the "reload" button in your browser/thunderbird every time you reload Firenvim.
`npm run build` is slow and performs lots of checks. In order to iterate faster, you can use `"$(npm bin)/webpack --env=firefox"` or `"$(npm bin)/webpack" --env=chrome` to build only for the target you care about. Make sure you click the "reload" button in your browser every time you reload Firenvim.

Firenvim's architecture is briefly described in [SECURITY.md](SECURITY.md). Firenvim is a webextension (it is a good idea to keep the [webextension documentation](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions) at hand if you're not familiar with webextension development). Webextensions are split in multiple processes. These processes communicate by sending messages to each other and have different entry points. Firenvim's entry points are:

- src/background.ts: Entry point of the background process.
- src/content.ts: Entry point of the content process (firefox & chrome only).
- src/compose.ts: Entry point of the compose window process (thunderbird only).
- src/frame.ts: Entry point of the Neovim Frame process.
- src/browserAction.ts: Entry point of the browser action process.

Expand All @@ -70,9 65,9 @@ The background process is started on browser startup and takes care of several t
- Logging errors and sending them to the browserAction.
- Forwarding messages from the Neovim Frame process to the content process and vice versa.

### Content & Compose process
### Content

The Content process and the Compose process perform the same tasks. They are created for each new tab/compose window. The tasks they perform are:
A Content process is created for each new tab. The tasks it performs are:

- Creating event listeners to detect when the user tries to interact with a "writable" element to then spawn a Neovim Frame process.
- Retrieving the content of said element and sending it to the Neovim Frame process.
Expand All @@ -83,8 78,8 @@ Reading and writing the content of "writable" elements requires interacting with

### Neovim Frame process

Neovim Frame process are created for each "writable" element the user wants to interact with. The role of the Neovim Frame process is to connect to the Neovim server started by the background process. This is done with a websocket. Once the connection has been made, the Neovim Frame process forwards keypresses to the Neovim server and displays the resulting screen updates. Handling keypresses is performed in `src/input.ts` by relying on the KeyHandler instantiated in either `src/frame.ts` or `src/compose.ts`. Updating the screen is performed by `src/renderer.ts`.
The Neovim Frame process creates a `BufWrite` autocommand to detect when the buffer is written to the disk. When this happens, it sends a request to the Content or Compose process and asks it to update the content of the "writable" element.
Neovim Frame process are created for each "writable" element the user wants to interact with. The role of the Neovim Frame process is to connect to the Neovim server started by the background process. This is done with a websocket. Once the connection has been made, the Neovim Frame process forwards keypresses to the Neovim server and displays the resulting screen updates. Handling keypresses is performed in `src/input.ts` by relying on the KeyHandler instantiated in `src/frame.ts`. Updating the screen is performed by `src/renderer.ts`.
The Neovim Frame process creates a `BufWrite` autocommand to detect when the buffer is written to the disk. When this happens, it sends a request to the Content process and asks it to update the content of the "writable" element.

### Browser Action process

Expand Down
5 changes: 0 additions & 5 deletions autoload/firenvim.vim
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 69,6 @@ function! firenvim#press_keys(...) abort
call rpcnotify(firenvim#get_chan(), 'firenvim_press_keys', l:keys)
endfunction

" Asks the browser extension to hide the firenvim frame
function! firenvim#thunderbird_send() abort
call rpcnotify(firenvim#get_chan(), 'firenvim_thunderbird_send', { 'text': nvim_buf_get_lines(0, 0, -1, 0) })
endfunction

" Turns a wsl path (forward slashes) into a windows one (backslashes)
function! s:to_windows_path(path) abort
if a:path[0] !=# '/'
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 42,7 @@
"license": "GPL-3.0",
"name": "Firenvim",
"scripts": {
"build": "webpack && web-ext build --source-dir target/firefox --artifacts-dir target/xpi --overwrite-dest -n firefox-latest.xpi && web-ext build --source-dir target/thunderbird --artifacts-dir target/xpi --overwrite-dest -n thunderbird-latest.xpi",
"build": "webpack && web-ext build --source-dir target/firefox --artifacts-dir target/xpi --overwrite-dest -n firefox-latest.xpi",
"clean": "rm -rf target",
"install_manifests": "nvim --headless -u NORC -i NONE -n -c \":set rtp =.\" -c \"call firenvim#install(1)\" -c \"quit\"",
"jest": "jest",
Expand Down
5 changes: 1 addition & 4 deletions release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 114,12 @@ sed 's/"key":\s*"[^"]*",//' -i target/chrome/manifest.json
rm -f target/chrome.zip
zip --junk-paths target/chrome.zip target/chrome/*
git archive "$newVersion" > target/firenvim-firefox-sources.tar.gz
git archive "$newVersion" > target/firenvim-thunderbird-sources.tar.gz

# Everythign went fine, we can push
git push
git push --tags
gh release create "$newVersion" target/chrome.zip target/xpi/firefox-latest.xpi target/xpi/thunderbird-latest.xpi --notes ""
gh release create "$newVersion" target/chrome.zip target/xpi/firefox-latest.xpi

firefox --private-window 'https://chrome.google.com/webstore/devconsole/g06704558984641971849/egpjdkipkomnmjhjmdamaniclmdlobbo/edit?hl=en'
sleep 1
firefox --private-window 'https://addons.mozilla.org/en-US/developers/addon/firenvim/versions/submit/'
sleep 1
firefox --private-window 'https://addons.thunderbird.net/en-US/developers/addon/firenvim/versions/submit/'
2 changes: 1 addition & 1 deletion src/KeyHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 15,7 @@ type KeydownEmittingObject = {
};

// This class implements the keydown logic that deals with modifiers and is
// shared across both browsers and thunderbird
// shared across both browsers
export class KeydownHandler extends EventEmitter<"input", (s: string) => void> implements KeyHandler {
private currentMode : NvimMode;
constructor(private elem: KeydownEmittingObject, settings: GlobalSettings) {
Expand Down
5 changes: 0 additions & 5 deletions src/Neovim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 117,6 @@ export async function neovim(
case "firenvim_vimleave":
lastLostFocus = performance.now();
return page.killEditor();
case "firenvim_thunderbird_send":
return browser.runtime.sendMessage({
args: [],
funcName: ["thunderbirdSend"],
});
}
});
});
Expand Down
92 changes: 6 additions & 86 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 15,7 @@
* content scripts. It rarely acts on its own.
*/
import { getGlobalConf, mergeWithDefaults } from "./utils/configuration";
import { getIconImageData, IconKind, isThunderbird } from "./utils/utils";
import { getIconImageData, IconKind } from "./utils/utils";

export let preloadedInstance: Promise<any>;

Expand Down Expand Up @@ -61,11 61,6 @@ async function updateIcon(tabid?: number) {
} else if (warning !== "") {
name = "notification";
}
// Can't test on the bird of thunder
/* istanbul ignore next */
if (isThunderbird()) {
return Promise.resolve();
}
return getIconImageData(name).then((imageData: any) => browser.browserAction.setIcon({ imageData }));
}

Expand Down Expand Up @@ -299,7 294,6 @@ Object.assign(window, {
},
getNvimPluginVersion: () => nvimPluginVersion,
getOwnFrameId: (sender: any) => sender.frameId,
getOwnComposeDetails: (sender: any) => (browser as any).compose.getComposeDetails(sender.tab.id),
getTab: (sender: any) => sender.tab,
getTabValue: (sender: any, args: any) => getTabValue(sender.tab.id, args[0]),
getTabValueFor: (_: any, args: any) => getTabValue(args[0], args[1]),
Expand All @@ -317,9 311,6 @@ Object.assign(window, {
return sender.frameId;
},
setTabValue: (sender: any, args: any) => setTabValue(sender.tab.id, args[0], args[1]),
thunderbirdSend: (sender: any) => {
return (browser as any).compose.sendMessage(sender.tab.id, { mode: 'default' });
},
toggleDisabled: () => toggleDisabled(),
updateSettings: () => updateSettings(),
openTroubleshootingGuide: () => browser.tabs.create({ active: true, url: "https://github.com/glacambre/firenvim/blob/master/TROUBLESHOOTING.md" }),
Expand Down Expand Up @@ -347,16 338,11 @@ browser.windows.onFocusChanged.addListener(async (windowId: number) => {

updateIcon();

// browser.commands doesn't exist in thunderbird. Else branch can't be covered
// so don't instrument the if.
/* istanbul ignore next */
if (!isThunderbird()) {
browser.commands.onCommand.addListener(acceptCommand);
browser.runtime.onMessageExternal.addListener(async (request: any, sender: any, _sendResponse: any) => {
const resp = await acceptCommand(request.command);
_sendResponse(resp);
});
}
browser.commands.onCommand.addListener(acceptCommand);
browser.runtime.onMessageExternal.addListener(async (request: any, sender: any, _sendResponse: any) => {
const resp = await acceptCommand(request.command);
_sendResponse(resp);
});

async function updateIfPossible() {
const tabs = await browser.tabs.query({});
Expand All @@ -381,69 367,3 @@ async function updateIfPossible() {
}
(window as any).updateIfPossible = updateIfPossible;
browser.runtime.onUpdateAvailable.addListener(updateIfPossible);

// Can't test on the bird of thunder
/* istanbul ignore next */
if (isThunderbird()) {
(browser as any).compose.onBeforeSend.addListener(async (tab: any, details: any) => {
const lines = (await browser.tabs.sendMessage(tab.id, { args: [], funcName: ["get_buf_content"] })) as string[];
// No need to remove the canvas when working with plaintext,
// thunderbird will do that for us.
if (details.isPlainText) {
// Firenvim has to cancel the beforeinput event on the compose
// window's documentElement in order to prevent the canvas from
// being destroyed. However, thunderbird has a bug where cancelling
// this event will prevent onBeforeSend from setting the compose
// window's content when editing plaintext emails.
// We work around this by telling the compose script to temporarily
// stop cancelling events.
await browser.tabs.sendMessage(tab.id, { args: [], funcName: ["pause_keyhandler"] });
return { cancel: false, details: { plainTextBody: lines.join("\n") } };
}

const doc = document.createElement("html");
const bod = document.createElement("body");
doc.appendChild(bod);

// Turn `>` into appropriate blockquote elements.
let previousQuoteLevel = 0;
let parent : HTMLElement = bod;
for (const l of lines) {
let currentQuoteLevel = 0;

// Count number of ">" symbols
let i = 0;
while (l[i] === " " || l[i] === ">") {
if (l[i] === ">") {
currentQuoteLevel = 1;
}
i = 1;
}

const line = l.slice(i);

if (currentQuoteLevel > previousQuoteLevel) {
for (let i = previousQuoteLevel; i < currentQuoteLevel; i) {
const block = document.createElement("blockquote");
block.setAttribute("type", "cite");
parent.appendChild(block);
parent = block;
}
} else if (currentQuoteLevel < previousQuoteLevel) {
for (let i = previousQuoteLevel; i > currentQuoteLevel; --i) {
parent = parent.parentElement;
}
}

parent.appendChild(document.createTextNode(line));
parent.appendChild(document.createElement("br"));

previousQuoteLevel = currentQuoteLevel;
}
return { cancel: false, details: { body: doc.outerHTML } };
});
// In thunderbird, register the script to be loaded in the compose window
(browser as any).composeScripts.register({
js: [{file: "compose.js"}],
});
}
134 changes: 0 additions & 134 deletions src/compose.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 4,8 @@ import { executeInPage } from "./utils/utils";
import { getConf } from "./utils/configuration";
import { keysToEvents } from "./utils/keys";

// This module is loaded in both the browser's content script, the browser's
// frame script and thunderbird's compose script.
// This module is loaded in both the browser's content script and the browser's
// frame script.
// As such, it should not have any side effects.

interface IGlobalState {
Expand Down
Loading

0 comments on commit b59c95e

Please sign in to comment.