Merge pull request #431 from ueokande/command-completions

Command completions
jh-changes
Shin'ya Ueoka 6 years ago committed by GitHub
commit 28bfa3ac81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/background/index.js
  2. 23
      src/background/reducers/index.js
  3. 80
      src/background/shared/completions/index.js
  4. 2
      src/background/shared/versions/index.js
  5. 0
      src/background/shared/versions/release-notes.js
  6. 0
      src/background/shared/versions/storage.js
  7. 3
      src/console/reducers/index.js
  8. 33
      src/content/reducers/index.js
  9. 11
      src/shared/commands/docs.js
  10. 8
      src/shared/settings/properties.js
  11. 4
      test/background/shared/versions/index.test.js
  12. 2
      test/background/shared/versions/storage.test.js

@ -6,7 +6,7 @@ import IndicatorComponent from 'background/components/indicator';
import reducers from 'background/reducers'; import reducers from 'background/reducers';
import { createStore, applyMiddleware } from 'redux'; import { createStore, applyMiddleware } from 'redux';
import promise from 'redux-promise'; import promise from 'redux-promise';
import * as versions from 'shared/versions'; import * as versions from './shared/versions';
const store = createStore( const store = createStore(
reducers, reducers,

@ -1,17 +1,8 @@
import settingReducer from './setting'; import { combineReducers } from 'redux';
import findReducer from './find'; import setting from './setting';
import tabReducer from './tab'; import find from './find';
import tab from './tab';
// Make setting reducer instead of re-use export default combineReducers({
const defaultState = { setting, find, tab,
setting: settingReducer(undefined, {}), });
find: findReducer(undefined, {}),
tab: tabReducer(undefined, {}),
};
export default function reducer(state = defaultState, action = {}) {
return { ...state,
setting: settingReducer(state.setting, action),
find: findReducer(state.find, action),
tab: tabReducer(state.tab, action), };
}

@ -1,6 +1,19 @@
import commandDocs from 'shared/commands/docs';
import * as tabs from './tabs'; import * as tabs from './tabs';
import * as histories from './histories'; import * as histories from './histories';
import * as bookmarks from './bookmarks'; import * as bookmarks from './bookmarks';
import * as properties from 'shared/settings/properties';
const completeCommands = (typing) => {
let keys = Object.keys(commandDocs);
return keys
.filter(name => name.startsWith(typing))
.map(name => ({
caption: name,
content: name,
url: commandDocs[name],
}));
};
const getSearchCompletions = (command, keywords, searchConfig) => { const getSearchCompletions = (command, keywords, searchConfig) => {
let engineNames = Object.keys(searchConfig.engines); let engineNames = Object.keys(searchConfig.engines);
@ -74,20 +87,63 @@ const getBufferCompletions = async(command, keywords, excludePinned) => {
]; ];
}; };
const getCompletions = (line, settings) => { const getSetCompletions = (command, keywords) => {
let typedWords = line.trim().split(/ +/); let keys = Object.keys(properties.docs).filter(
let typing = ''; name => name.startsWith(keywords)
if (!line.endsWith(' ')) { );
typing = typedWords.pop(); let items = keys.map((key) => {
if (properties.types[key] === 'boolean') {
return [
{
caption: key,
content: command + ' ' + key,
url: 'Enable ' + properties.docs[key],
}, {
caption: 'no' + key,
content: command + ' no' + key,
url: 'Disable ' + properties.docs[key],
}
];
}
return [
{
caption: key,
content: command + ' ' + key,
url: 'Set ' + properties.docs[key],
}
];
});
items = items.reduce((acc, val) => acc.concat(val), []);
if (items.length === 0) {
return Promise.resolve([]);
} }
return Promise.resolve([
{
name: 'Properties',
items,
}
]);
};
if (typedWords.length === 0) { const complete = (line, settings) => {
let trimmed = line.trimStart();
let words = trimmed.split(/ +/);
let name = words[0];
if (words.length === 1) {
let items = completeCommands(name);
if (items.length === 0) {
return Promise.resolve([]); return Promise.resolve([]);
} }
let name = typedWords.shift(); return Promise.resolve([
let keywords = typedWords.concat(typing).join(' '); {
name: 'Console Command',
items: completeCommands(name),
}
]);
}
let keywords = trimmed.slice(name.length).trimStart();
switch (name) { switch (words[0]) {
case 'o': case 'o':
case 'open': case 'open':
case 't': case 't':
@ -108,12 +164,10 @@ const getCompletions = (line, settings) => {
case 'bdelete': case 'bdelete':
case 'bdeletes': case 'bdeletes':
return getBufferCompletions(name, keywords, true); return getBufferCompletions(name, keywords, true);
case 'set':
return getSetCompletions(name, keywords);
} }
return Promise.resolve([]); return Promise.resolve([]);
}; };
const complete = (line, settings) => {
return getCompletions(line, settings);
};
export { complete }; export { complete };

@ -1,6 +1,6 @@
import * as storage from './storage'; import * as storage from './storage';
import * as releaseNotes from './release-notes'; import * as releaseNotes from './release-notes';
import manifest from '../../../manifest.json'; import manifest from '../../../../manifest.json';
const NOTIFICATION_ID = 'vimvixen-update'; const NOTIFICATION_ID = 'vimvixen-update';

@ -11,6 +11,9 @@ const defaultState = {
}; };
const nextSelection = (state) => { const nextSelection = (state) => {
if (state.completions.length === 0) {
return [-1, -1];
}
if (state.groupSelection < 0) { if (state.groupSelection < 0) {
return [0, 0]; return [0, 0];
} }

@ -1,25 +1,10 @@
import addonReducer from './addon'; import { combineReducers } from 'redux';
import findReducer from './find'; import addon from './addon';
import settingReducer from './setting'; import find from './find';
import inputReducer from './input'; import setting from './setting';
import followControllerReducer from './follow-controller'; import input from './input';
import followController from './follow-controller';
// Make setting reducer instead of re-use export default combineReducers({
const defaultState = { addon, find, setting, input, followController,
addon: addonReducer(undefined, {}), });
find: findReducer(undefined, {}),
setting: settingReducer(undefined, {}),
input: inputReducer(undefined, {}),
followController: followControllerReducer(undefined, {}),
};
export default function reducer(state = defaultState, action = {}) {
return {
...state,
addon: addonReducer(state.addon, action),
find: findReducer(state.find, action),
setting: settingReducer(state.setting, action),
input: inputReducer(state.input, action),
followController: followControllerReducer(state.followController, action),
};
}

@ -0,0 +1,11 @@
export default {
set: 'Set a value of the property',
open: 'Open a URL or search by keywords in current tab',
tabopen: 'Open a URL or search by keywords in new tab',
winopen: 'Open a URL or search by keywords in new window',
buffer: 'Sekect tabs by matched keywords',
bdelete: 'Close a certain tab matched by keywords',
bdeletes: 'Close all tabs matched by keywords',
quit: 'Close the current tab',
quitall: 'Close all tabs',
};

@ -15,4 +15,10 @@ const defaults = {
adjacenttab: true, adjacenttab: true,
}; };
export { types, defaults }; const docs = {
hintchars: 'Hint characters on follow mode',
smoothscroll: 'smooth scroll',
adjacenttab: 'open adjacent tabs',
};
export { types, defaults, docs };

@ -1,5 +1,5 @@
import * as versions from 'shared/versions'; import * as versions from 'background/shared/versions';
import manifest from '../../../manifest.json'; import manifest from '../../../../manifest.json';
describe("shared/versions/storage", () => { describe("shared/versions/storage", () => {
describe('#checkUpdated', () => { describe('#checkUpdated', () => {

@ -1,4 +1,4 @@
import * as storage from 'shared/versions/storage'; import * as storage from 'background/shared/versions/storage';
describe("shared/versions/storage", () => { describe("shared/versions/storage", () => {
describe('#load', () => { describe('#load', () => {