有馬総一郎のブログ

(彼氏の事情)

Vimperatorに取って代われるかも知れないアドオンVimFx

VimperatorがFirefox 51で動かなくなり、自分で修正xpiをインストールしたりしてたのだけど、その時、 Vimperatorを代替できるアドオンとしてVimFxなるものの存在を知り、それ以降はずっと VimFxを使っている。

VimFx メモ - クマーなひとときv2←こちらのブログを見て頂ければ、それで事足りる。私の設定も殆ど、ここからのパクりだ。以下、私の戯言を読みたい人はどうぞ。

修正されたvimperator 3.16.0であっても、マルチプロセスウィンドウが有効の状態では、TypeError: 'stopPropagation' called on an object that does not implement interface Event.というエラーが出てまともに動かない。

マルチプロセスウィンドウ有効化の設定↓

user_pref("extensions.e10sBlocksEnabling", true);
user_pref("extensions.e10sBlockedByAddons", true);

しかし、 VimFxならマルチプロセスウィンドウが有効でも正常に動く。そう VimFxならね。

1 Vimperatorに取って代われるかも知れないアドオン

2 Vimiumとは違うぜ

初め、ノーマルモードに戻ろうとするのが escでなければ上手く動かず、「糞!」と思ったけど、<force><c-[>とすれば、ちゃんと機能した。

tabduplicateコマンドないから「タブ複製できねーじゃん」とか思ったら、ytで可能。historyコマンドないから「履歴開けねーじゃん」とか思ったら、gHで可能。

タブの選択もg0g$といった形でタブ先頭、タブ最終を選べるし、4gtとすれば右タブ4個移動なるのでタブ移動も問題なし。そもそもFirefoxの標準ショートカットキーでAlt+1からAlt+9(数字は右から数えて何番目のタブか)といった形でタブ移動が可能。

他にも Vimperatorでは標準ではできなかったであろう、 ブラウザ要素の選択(というのか、ブラウザのローケションバー、ツールバーを含む上部というか…)がebで可能。ヒントモードでの 重なったマーカー文字を前後を入れ替えc-spaces-spaceで可能。 要素のコンテキストメニューを開くなんてこともできる(ec)。

Vimperatorでは、キャレットモードにするために、一度適当な文字を検索して、それからcを押していたが、 要素にキャレットを置く(v)で近い要素を選択してのキャレットモードへの移行が一度で行える。

qmark a https://anime.dmkt-sp.jp/animestore/tp_pc

といったクイックマークも

'custom.mode.normal.open_danime_store': 'goa',
[
  {
    name: 'open_danime_store',
    description: 'Dアニメストアを開く',
  }, ({vim}) => {
    let location = new vim.window.URL(vim.browser.currentURI.spec)
    vim.window.gBrowser.loadURI('https://anime.dmkt-sp.jp/animestore/tp_pc')
  }
],

といったような形(vimfx.addCommandvimfx.set)で可能( 上記のコードをそのまま書いても動かないので注意)。

nnoremap ecc :emenu ツール.Default User Agent.Browsers - Windows.Chrome 45.0 (Windows 10 - 64 bit)<CR>
nnoremap ep :emenu ブックマーク.Pocket のリストを表示<CR>
nnoremap ef :emenu ツール.Web 開発.FireFTP<CR>

といったemenuコマンドが使えないのは辛いが、ブラウザ要素の選択が可能なことから、 DOM Inspectorをインストールし、chrome://browser/content/browser.xulを開く。


アドオン DOM Inspector


ブラウザのUIを呼び出す

そして、 ツール -> Web開発 -> DOM InspectorDOM Inspectorを起動し、 Find a node to insepect by clicking on itでクリックした要素のIDを調べて、以下のように記述すれば、ツールバーをクリックすることも可能となる。他にもノーマルモードやキャレットモードで選択した文字列を使って特定のURLに向けて投げたりといったこともできる。

[
  {
    name: 'click_toolbar_pocket',
    description: 'Click toolbar button [Pocket]'
  }, ({vim}) => {
    vim.window.document.getElementById('pocket-button').click();
  }
],


ツール -> Web開発 -> DOM Inspector


クリックした要素のIDを調べる

私がFirefoxを使い続けている一つの理由は Vimperatorだった。しかし、Firefox 51から VimFxに乗り替えて2ヶ月ぐらいになるが、十分満足している。ヒントモードがある程度動けば、コマンドがそんな使えなくてもいいというライトユーザーなので、 VimFxでやりたいことはほぼやれている。

設定ファイルはVimFx/config-file.md at master · akhodakivskiy/VimFx · GitHubの通り、

user_pref("extensions.VimFx.config_file_directory", "~/.vimfx");

でディレクトリ指定して、そこにusr.jsframe.jsを置いてそこに記述すればOK。Share your config file · akhodakivskiy/VimFx Wiki · GitHubというconfig.jsの紹介一覧ページがある。

設定ファイルの読取はgC。エラーが起きたとき、コンソールで確認できるとあるけど、何故かできなかった。

また、設定ファイルの読み取りに成功したのに、vimfx.setでのショートカットが動かない場合は?でショートカット一覧を表示して、設定したショートカットが正しく指定モードに記述されているか確認するといいかも知れない。

ssといったショートカットを設定しても、sのショートカットがある場合、途中のショートカットsが動いてしまうため、ssのキーの割り当てはできないみたいだ。

絶賛した VimFxだけども、不満もある。アドレスバーにフォーカスした時にWindows以外だとIMEの制御ができない(ヒントモードではIMEを特に意識しなくても動作する)。そして、qmarkemenuみたいに簡単にカスタマイズ設定を記述できないこと。設定ファイルの記述が多くなる。

なにより、ただでさえ Vimperatorでも情報が少ないのに、 VimFxとなると、もっと情報が減ってしまう。公式ドキュメントは、かなり充実してるのでちゃんと読み解いていけばかなりのことが解決するのかも知れないが、やはり英語なのと、Firefox、Javascriptの知識がないので辛い…今後もっとVimFxユーザーが増えることを期待したい。

最後に、私のコピペ設定を貼っておく(先に設定ファイルを残してくれた方々感謝)。

config.jsconfig.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const gClipboardHelper = Cc['@mozilla.org/widget/clipboardhelper;1']
      .getService(Ci.nsIClipboardHelper);
const {Preferences} = Cu.import('resource://gre/modules/Preferences.jsm', {});

const VIMFX_PREFS = {
  'prevent_autofocus': true,
  'blacklist': 'https://feedly.com/i/latest  https://tweetdeck.twitter.com/',
  'hints.chars': 'abcdefghijklmnopqrstuvwxyz',
  'prev_patterns': 'prev  previous  back  newer  ^前(の)?ページ  前.*  ←  ^<$  ^(<<|≪)$  ^(<|≪)  (<|≪)$  ^前(へ|の|ペ)  ^戻る  prev|previous  ^(<<|«)$  ^(<|«)  (<|«)$',
  'next_patterns': 'next  more  older  ^次(の)?ページ  次.*  →  ^>$  ^(>>|≫)$  ^(>|≫)  (>|≫)$  ^次(へ|の|ペ)  ^続き  ^(>>|»)$  ^(>|»)  (>|»)$',
};

const MAPPINGS = {
  'mode.normal.copy_current_url': 'yy',
  'mode.normal.go_home': 'gh',
  'mode.normal.history_back': 'H',
  'mode.normal.history_forward': 'L',
  'mode.normal.stop': '<c-escape>',
  'mode.normal.stop_all': 'a<c-escape>',
  'mode.normal.scroll_left': 'h',
  'mode.normal.scroll_right': 'l',
  'mode.normal.scroll_page_down': '<c-f>',
  'mode.normal.scroll_page_up': '<c-b>',
  'mode.normal.scroll_half_page_down': '<c-d>',
  'mode.normal.scroll_half_page_up': '<c-u>',
  'mode.normal.mark_scroll_position': 'mm',
  'mode.normal.scroll_to_mark': 'gm',
  'mode.normal.tab_new': 'T',
  'mode.normal.tab_new_after_current': 't',
  'mode.normal.tab_select_previous': 'gT',
  'mode.normal.tab_select_next': 'gt',
  'mode.normal.tab_select_first_non_pinned': 'g^',
  'mode.normal.tab_select_last': 'g$',
  'mode.normal.tab_close': 'x',
  'mode.normal.tab_restore': 'u',
  'mode.normal.tab_restore_list': ',uu',
  'mode.normal.follow_previous': '[[',
  'mode.normal.follow_next': ']]',
  'mode.normal.enter_mode_ignore': 'I',
  'mode.normal.quote': 'i',
  'mode.normal.esc': '<force><escape> <force><c-[>',
  'mode.caret.exit': '<escape> <c-[>',
  'mode.hints.exit': '<escape> <c-[>',
  'mode.find.exit': '<escape> <enter> <c-[>',
  'mode.marks.exit': '<escape>  <c-[>',
  'custom.mode.normal.click_toolbar_pocket': 'cp',
  'custom.mode.normal.copy_as_markdown': 'ym',
  'custom.mode.normal.copy_title_and_url': 'yc',
  'custom.mode.normal.view_source': 'gf',
  'custom.mode.normal.open_danime_store': 'goa',
  'custom.mode.normal.open_browser': 'gob',
  'custom.mode.normal.open_aws_console': 'goc',
  'custom.mode.normal.open_feedly': 'gof',
  'custom.mode.normal.open_pocket': 'gop',
  'custom.mode.normal.open_simplenote': 'gos',
  'custom.mode.normal.start_tweetdeck': 'got',
  'custom.mode.normal.open_addons': 'addon',
  'custom.mode.normal.zoom_in': 'zi',
  'custom.mode.normal.zoom_out': 'zo',
  'custom.mode.normal.zoom_reset': 'z0',
  'custom.mode.normal.search_selected_text': 'sst',
  'custom.mode.normal.selected_google_translate': 'sgt',
  'custom.mode.normal.selected_url_open': 'suo',
  'custom.mode.caret.search_selected_text': 's',
  'custom.mode.caret.selected_google_translate': 't',
  'custom.mode.caret.selected_url_open': 'u',
  'custom.mode.normal.tab_move_to_index': 'mi',
  'custom.mode.normal.goto_tab': 'b',
};

const {commands} = vimfx.modes.normal;

const CUSTOM_COMMANDS = [
  [
    {
      name: 'copy_as_markdown',
      description: 'Copy title and url as Markdown',
      category: 'location',
      order: commands.copy_current_url.order + 2
    }, ({vim}) => {
      let url = vim.window.gBrowser.selectedBrowser.currentURI.spec;
      let title = vim.window.gBrowser.selectedBrowser.contentTitle;
      let s = `[${title}](${url})`;
      gClipboardHelper.copyString(s);
      vim.notify(`Copied to clipboard: ${s}`);
    }
  ],
  [
    {
      name: 'copy_title_and_url',
      description: 'Copy title and url',
      category: 'location',
      order: commands.copy_current_url.order + 1
    }, ({vim}) => {
      let url = vim.window.gBrowser.selectedBrowser.currentURI.spec;
      let title = vim.window.gBrowser.selectedBrowser.contentTitle;
      let s = `${title}\n${url}`;
      gClipboardHelper.copyString(s);
      vim.notify(`Copied to clipboard: ${s}`);
    }
  ],
  [
    {
      name: 'click_toolbar_pocket',
      description: 'Click toolbar button [Pocket]'
    }, ({vim}) => {
      vim.window.document.getElementById('pocket-button').click();
    }
  ],
  [
    {
      name: 'view_source',
      description: 'ページのソースを表示',
    }, ({vim}) => {
      let url = vim.window.gBrowser.selectedBrowser.currentURI.spec;
      if ( url.includes('view-source:') ) {
        url = url.replace(/^view-source:/, '');
      } else {
        url = `view-source:${url}`
      }
      let location = new vim.window.URL(vim.browser.currentURI.spec)
      vim.window.gBrowser.loadURI(`${url}`)
    }
  ],
  [
    {
      name: 'open_danime_store',
      description: 'Dアニメストアを開く',
    }, ({vim}) => {
      let location = new vim.window.URL(vim.browser.currentURI.spec)
      vim.window.gBrowser.loadURI('https://anime.dmkt-sp.jp/animestore/tp_pc')
    }
  ],
  [
    {
      name: 'open_aws_console',
      description: 'AWSコンソールを開く',
    }, ({vim}) => {
      let location = new vim.window.URL(vim.browser.currentURI.spec)
      vim.window.gBrowser.loadURI('https://console.aws.amazon.com/')
    }
  ],
  [
    {
      name: 'start_tweetdeck',
      description: 'tweetdeckを始める',
    }, ({vim}) => {
      let location = new vim.window.URL(vim.browser.currentURI.spec)
      vim.window.gBrowser.loadURI('https://tweetdeck.twitter.com/')
    }
  ],
  [
    {
      name: 'open_simplenote',
      description: 'simplenoteを開く',
    }, ({vim}) => {
      let location = new vim.window.URL(vim.browser.currentURI.spec)
      vim.window.gBrowser.loadURI('https://app.simplenote.com/')
    }
  ],
  [
    {
      name: 'open_feedly',
      description: 'Feedlyを開く',
    }, ({vim}) => {
      let location = new vim.window.URL(vim.browser.currentURI.spec)
      vim.window.gBrowser.loadURI('https://feedly.com/i/latest')
    }
  ],
  [
    {
      name: 'open_pocket',
      description: 'Pocketを開く',
    }, ({vim}) => {
      let location = new vim.window.URL(vim.browser.currentURI.spec)
      vim.window.gBrowser.loadURI('https://getpocket.com/a/')
    }
  ],
  [
    {
      name: 'open_browser',
      description: 'Chrome URI Browserを開く',
    }, ({vim}) => {
      let location = new vim.window.URL(vim.browser.currentURI.spec)
      vim.window.gBrowser.loadURI('chrome://browser/content/browser.xul')
    }

  ],
  [
    {
      name: 'open_addons',
      description: 'アドオンを開く',
    }, ({vim}) => {
      let location = new vim.window.URL(vim.browser.currentURI.spec)
      vim.window.gBrowser.loadURI('about:addons')
    }

  ],
  [
    {
      name: 'zoom_reset',
      description: 'ズームリセット',
    }, ({vim}) => {
      vim.window.FullZoom.reset();
    }
  ],
  [
    {
      name: 'zoom_out',
      description: 'ズームアウト',
    }, ({vim}) => {
      vim.window.FullZoom.reduce();
    }
  ],
  [
    {
      name: 'zoom_in',
      description: 'ズームイン',
    }, ({vim}) => {
      vim.window.FullZoom.enlarge();
    }
  ],
  [
    {
      name: 'search_selected_text',
      description: 'Search for the selected text',
      mode: 'normal',
    }, ({vim}) => {
      //let {messageManager} = vim.window.gBrowser.selectedBrowser
      vimfx.send(vim, 'getSelection', null, selection => {
        let inTab = true // Change to 'false' if you'd like to search in current tab.
        vim.window.BrowserSearch.loadSearch(selection, inTab)
      })
    }
  ],
  [
    {
      name: 'selected_google_translate',
      description: '選択文字列をGoogle翻訳',
      mode: 'normal',
    }, ({vim}) => {
      vimfx.send(vim, 'getSelection', null, selection => {
        vim.window.switchToTabHavingURI('http://translate.google.co.jp/?source=osdd#auto|auto|'+selection, true)
      })
    }
  ],
  [
    {
      name: 'selected_url_open',
      description: '選択URLを開く',
      mode: 'normal',
    }, ({vim}) => {
      vimfx.send(vim, 'getSelection', null, selection => {
        let url = selection;
        if ( !selection.includes('http') ) {
          url = 'http://' + selection;
        }
        vim.window.switchToTabHavingURI(url, true)
      })
    }
  ],
  [
    {
      name: 'search_selected_text',
      description: 'Search for the selected text',
      mode: 'caret',
    }, ({vim}) => {
      //let {messageManager} = vim.window.gBrowser.selectedBrowser
      vimfx.send(vim, 'getSelection', null, selection => {
        let inTab = true // Change to 'false' if you'd like to search in current tab.
        vim.window.BrowserSearch.loadSearch(selection, inTab)
      })
    }
  ],
  [
    {
      name: 'selected_google_translate',
      description: '選択文字列をGoogle翻訳',
      mode: 'caret',
    }, ({vim}) => {
      vimfx.send(vim, 'getSelection', null, selection => {
        vim.window.switchToTabHavingURI('http://translate.google.co.jp/?source=osdd#auto|auto|'+selection, true)
      })
    }
  ],
  [
    {
      name: 'selected_url_open',
      description: '選択URLを開く',
      mode: 'caret',
    }, ({vim}) => {
      vimfx.send(vim, 'getSelection', null, selection => {
        let url = selection;
        if ( !selection.includes('http') ) {
          url = 'http://' + selection;
        }
        vim.window.switchToTabHavingURI(url, true)
      })
    }
  ],
  [
    {
      name: 'tab_move_to_inex',
      description: 'Move tab to index',
      category: 'tabs',
      order: commands.tab_move_forward.order + 1,
    }, ({vim, count}) => {
      if (count === undefined) {
        vim.notify('Provide a count')
        return
      }
      let {window} = vim
      window.setTimeout(() => {
        let {selectedTab} = window.gBrowser
        if (selectedTab.pinned) {
          vim.notify('Run from a non-pinned tab')
          return
        }
        let newPosition = window.gBrowser._numPinnedTabs + count - 1
        window.gBrowser.moveTabTo(selectedTab, newPosition)
      }, 0)
    }
  ],
  [
    {
      name: 'goto_tab',
      description: 'Goto tab',
      category: 'tabs',
    }, function(args) {
      commands.focus_location_bar.run(args);
      args.vim.window.gURLBar.value = '% ';
    }
  ]
];

Object.entries(VIMFX_PREFS).forEach(([name, value]) => {
  vimfx.set(name, value);
});

CUSTOM_COMMANDS.forEach(([options, fn]) => {
  vimfx.addCommand(options, fn);
});

Object.entries(MAPPINGS).forEach(([cmd, key]) => {
  if (!cmd.includes('.')) {
    cmd = `mode.normal.${cmd}`;
  }
  vimfx.set(cmd, key);
});
frame.jsframe.js
1
2
3
4
5
//sendAsyncMessage('VimFx-config:tabCreated')
vimfx.listen('getSelection', (data, callback) => {
  let selection = content.getSelection().toString()
  callback(selection)
})
userChrome.css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);

#VimFxMarkersContainer .marker {
    font-size: 14px !important;
}

/* Make location bar red while in ignore mode */
#main-window[vimfx-mode="ignore"] #urlbar {
    background: red !important;
}

statuspanel label.statuspanel-label {
    background: linear-gradient(45deg, rgba(22, 22, 22, 0.9), rgba(99, 99, 99, 0.9)) !important;
    color: whitesmoke !important;
    font-size: 14px !important;
}

#urlbar {
    ime-mode: inactive;
}
#TabsToolbar {
    counter-reset: tabs-counter;
}

.tab-close-button:not([pinned]) {
  visibility: hidden;
  display: block;
  color: inherit;
  counter-increment: tabs-counter;

  &::before {
    content: counter(tabs-counter);
    visibility: visible;
    font-weight: normal;
    font-style: normal;
  }
}

  1. ●まんが/瀬尾浩史
    ●デザイン/シオズミタロウ
    ●初出 /株式会社アスキー・メディアワークス「 Ubuntu Magazine Japan vol.09 」
    (http://ubuntu.asciimw.jp/)2012 年 9 月 6 日発行

  2. ●まんが/瀬尾浩史
    ●デザイン/シオズミタロウ
    ●初出 /株式会社アスキー・メディアワークス「 Ubuntu Magazine Japan vol.09 」
    (http://ubuntu.asciimw.jp/)2012 年 9 月 6 日発行

[cate: mozilla ] [tags: Firefox ]

« 動画の表示領域を特定の範囲に切り抜く(Crop) UbuntuでQRコードを読み取る »

Comments