diff options
Diffstat (limited to 'src/background/shared/completions')
| -rw-r--r-- | src/background/shared/completions/histories.js | 83 | ||||
| -rw-r--r-- | src/background/shared/completions/index.js | 84 | ||||
| -rw-r--r-- | src/background/shared/completions/tabs.js | 10 | 
3 files changed, 177 insertions, 0 deletions
| diff --git a/src/background/shared/completions/histories.js b/src/background/shared/completions/histories.js new file mode 100644 index 0000000..a7d3d47 --- /dev/null +++ b/src/background/shared/completions/histories.js @@ -0,0 +1,83 @@ +const filterHttp = (items) => { +  const httpsHosts = items +    .filter(item => item[1].protocol === 'https:') +    .map(item => item[1].host); +  const httpsHostSet = new Set(httpsHosts); +  return items.filter( +    item => !(item[1].protocol === 'http:' && httpsHostSet.has(item[1].host)) +  ); +}; + +const filterEmptyTitle = (items) => { +  return items.filter(item => item[0].title && item[0].title !== ''); +}; + +const filterClosedPath = (items) => { +  const allSimplePaths = items +    .filter(item => item[1].hash === '' && item[1].search === '') +    .map(item => item[1].origin + item[1].pathname); +  const allSimplePathSet = new Set(allSimplePaths); +  return items.filter( +    item => !(item[1].hash === '' && item[1].search === '' && +      (/\/$/).test(item[1].pathname) && +      allSimplePathSet.has( +        (item[1].origin + item[1].pathname).replace(/\/$/, '') +      ) +    ) +  ); +}; + +const reduceByPathname = (items, min) => { +  let hash = {}; +  for (let item of items) { +    let pathname = item[1].origin + item[1].pathname; +    if (!hash[pathname]) { +      hash[pathname] = item; +    } else if (hash[pathname][1].href.length > item[1].href.length) { +      hash[pathname] = item; +    } +  } +  let filtered = Object.values(hash); +  if (filtered.length < min) { +    return items; +  } +  return filtered; +}; + +const reduceByOrigin = (items, min) => { +  let hash = {}; +  for (let item of items) { +    let origin = item[1].origin; +    if (!hash[origin]) { +      hash[origin] = item; +    } else if (hash[origin][1].href.length > item[1].href.length) { +      hash[origin] = item; +    } +  } +  let filtered = Object.values(hash); +  if (filtered.length < min) { +    return items; +  } +  return filtered; +}; + +const getCompletions = (keyword) => { +  return browser.history.search({ +    text: keyword, +    startTime: 0, +  }).then((historyItems) => { +    return [historyItems.map(item => [item, new URL(item.url)])] +      .map(filterEmptyTitle) +      .map(filterHttp) +      .map(filterClosedPath) +      .map(items => reduceByPathname(items, 10)) +      .map(items => reduceByOrigin(items, 10)) +      .map(items => items +        .sort((x, y) => x[0].visitCount < y[0].visitCount) +        .slice(0, 10) +        .map(item => item[0]) +      )[0]; +  }); +}; + +export { getCompletions }; diff --git a/src/background/shared/completions/index.js b/src/background/shared/completions/index.js new file mode 100644 index 0000000..73b7b27 --- /dev/null +++ b/src/background/shared/completions/index.js @@ -0,0 +1,84 @@ +import * as tabs from './tabs'; +import * as histories from './histories'; + +const getOpenCompletions = (command, keywords, searchConfig) => { +  return histories.getCompletions(keywords).then((pages) => { +    let historyItems = pages.map((page) => { +      return { +        caption: page.title, +        content: command + ' ' + page.url, +        url: page.url +      }; +    }); +    let engineNames = Object.keys(searchConfig.engines); +    let engineItems = engineNames.filter(name => name.startsWith(keywords)) +      .map(name => ({ +        caption: name, +        content: command + ' ' + name +      })); + +    let completions = []; +    if (engineItems.length > 0) { +      completions.push({ +        name: 'Search Engines', +        items: engineItems +      }); +    } +    if (historyItems.length > 0) { +      completions.push({ +        name: 'History', +        items: historyItems +      }); +    } +    return completions; +  }); +}; + +const getCompletions = (line, settings) => { +  let typedWords = line.trim().split(/ +/); +  let typing = ''; +  if (!line.endsWith(' ')) { +    typing = typedWords.pop(); +  } + +  if (typedWords.length === 0) { +    return Promise.resolve([]); +  } +  let name = typedWords.shift(); +  let keywords = typedWords.concat(typing).join(' '); + +  switch (name) { +  case 'o': +  case 'open': +  case 't': +  case 'tabopen': +  case 'w': +  case 'winopen': +    return getOpenCompletions(name, keywords, settings.search); +  case 'b': +  case 'buffer': +    return tabs.getCompletions(keywords).then((gotTabs) => { +      let items = gotTabs.map((tab) => { +        return { +          caption: tab.title, +          content: name + ' ' + tab.title, +          url: tab.url, +          icon: tab.favIconUrl +        }; +      }); +      return [ +        { +          name: 'Buffers', +          items: items +        } +      ]; +    }); +  } +  return Promise.resolve([]); +}; + +const complete = (line, settings) => { +  return getCompletions(line, settings); +}; + +export { complete }; diff --git a/src/background/shared/completions/tabs.js b/src/background/shared/completions/tabs.js new file mode 100644 index 0000000..5edddca --- /dev/null +++ b/src/background/shared/completions/tabs.js @@ -0,0 +1,10 @@ +const getCompletions = (keyword) => { +  return browser.tabs.query({ currentWindow: true }).then((tabs) => { +    let matched = tabs.filter((t) => { +      return t.url.includes(keyword) || t.title && t.title.includes(keyword); +    }); +    return matched; +  }); +}; + +export { getCompletions }; | 
