Skip to content

Commit

Permalink
feat: Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
brpaz committed Jul 31, 2019
0 parents commit f346a10
Show file tree
Hide file tree
Showing 16 changed files with 397 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: 2
jobs:
build:
docker:
- image: circleci/python:3.6.4
steps:
- checkout
- run: sudo pip3 install pylint yapf
- run: make lint


21 changes: 21 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org

root = true

[*]

# Change these settings to your own preference
indent_style = space
indent_size = 4

# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.pyc
__pycache__
.cache
*.log
.vscode
17 changes: 17 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[MESSAGES CONTROL]

# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time. See also the "--disable" option for examples.
#enable=

# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=locally-disabled,too-few-public-methods
27 changes: 27 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

EXT_NAME:=com.github.brpaz.ulauncher-docsearch
EXT_DIR:=$(shell pwd)

.PHONY: help lint format link unlink deps dev
.DEFAULT_TARGET: help

help: ## Show help menu
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

lint: ## Run Pylint
@find . -iname "*.py" | xargs pylint

format: ## Format code using yapf
@yapf --in-place --recursive .

link: ## Symlink the project source directory with Ulauncher extensions dir.
@ln -s ${EXT_DIR} ~/.cache/ulauncher_cache/extensions/${EXT_NAME}

unlink: ## Unlink extension from Ulauncher
@rm -r ~/.cache/ulauncher_cache/extensions/${EXT_NAME}

deps: ## Install Python Dependencies
@pip3 install -r requirements.txt

dev: ## Runs ulauncher on development mode
ulauncher --no-extensions --dev -v
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# ulauncher-docsearch

[![Ulauncher Extension](https://img.shields.io/badge/Ulauncher-Extension-green.svg?style=for-the-badge)](https://ext.ulauncher.io/-/github-brpaz-ulauncher-docsearch)
[![CircleCI](https://img.shields.io/circleci/build/github/brpaz/ulauncher-docsearch.svg?style=for-the-badge)](https://circleci.com/gh/brpaz/ulauncher-docsearch)
![License](https://img.shields.io/github/license/brpaz/ulauncher-docsearch.svg?style=for-the-badge)

![Algolia](images/search-by-algolia-light-background.svg)

> Full text search on Documentation sites, powered by [Algolia](https://www.algolia.com/).
**This is a work in progress project and its not ready to be used yet.**

## Motivation

Searching documentation is a constant need but not an easy task. Switch contexts between your code editor to the browser, remember the documentation site url and then find what you need. Many times, I kwew exactly what I want to find and that I have seen before, but simple cant find it again.

This extension, aims to make documentation search less painfull, allowing you to a full text search on popular documentation sites directly from directly from ulauncher.

## Features

This extension allows to easily search on popular documentation websites, using [Algolia DocSearch](https://community.algolia.com/docsearch/).



## Usage

![demo](demo.gif)

## Requirements

* Ulauncher V5
* Python 3
* algoliasearch>=2.0,<3.0 (install with pip3)

## Install

Open ulauncher preferences window -> extensions -> add extension and paste the following url:

```
https://github.com/brpaz/ulauncher-docsearch
```

## Development

```
git clone https://github.com/brpaz/ulauncher-docsearch
make link
```

The `make link` command will symlink the cloned repo into the appropriate location on the ulauncher extensions folder.

To see your changes, stop ulauncher and run it from the command line with: `ulauncher -v`.

## Contributing

All contributions are welcome.

## Show your support

<a href="https://www.buymeacoffee.com/Z1Bu6asGV" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>


## License

Copywright @ 2019 [Bruno Paz](https://github.com/brpaz)

This project is [MIT](LLICENSE) Licensed.

10 changes: 10 additions & 0 deletions data/docsets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"react" : {
"name": "React",
"description": "A JavaScript library for building user interfaces",
"icon": "images/docs/react.png",
"algolia_index": "react",
"keyword": "reactdocs",
"url": "https://reactjs.org/docs/getting-started.html"
}
}
Binary file added demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions docs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""
Module responsible for search into docs
"""

import json
import os
from algoliasearch.search_client import SearchClient

ALGOLIA_APPLICAITON_ID = 'BH4D9OD16A'
ALGOLIA_API_KEY = '36221914cce388c46d0420343e0bb32e'

DEFAULT_DOC_IMAGE = 'images/icon.png'

class DocSearch:
""" Searches Docs """

def __init__(self):
""" Class constructor """

self.algolia_client = SearchClient.create(ALGOLIA_APPLICAITON_ID, ALGOLIA_API_KEY)
self.docsets = {}

with open(os.path.join(os.path.dirname(__file__), 'data', 'docsets.json'), 'r') as data:
self.docsets = json.load(data)

def get_available_docs(self, filter_term):
""" Returns a list of available docs """
docs = []
for key, value in self.docsets.items():
docs.append({
'key': key,
'name': value['name'],
'description': value['description'],
'icon': value['icon'],
'url': value['url']
})

if filter_term:
docs = [x for x in docs if filter_term.lower() in x['name'].lower()]

return docs

def has_docset(self, key):
""" Checks if the specified docset exists """
return key in self.docsets

def get_docset(self, key):
""" Returns the details from a docset with the specified key passed as argument """

if key in self.docsets.keys():
return self.docsets[key]

return None

def search(self, docset, term):
""" Searches a term on a specific docset and return the results """

docset = self.get_docset(docset)

if not docset:
raise ValueError("The specified docset is not known")

index = self.algolia_client.init_index(docset['algolia_index'])
search_results = index.search(term)

if not search_results['hits']:
return []

items = []
for hit in search_results['hits']:
title, description = self.parse_item_description(hit)
items.append({
'url': hit['url'],
'title': title,
'icon': docset['icon'],
'category': description
})

return items

def parse_item_description(self, hit):
""" Returns the text to display as result item title """
hierarchy = hit['hierarchy'].values()

# Filter the list by removing the empty values
res = [i for i in hierarchy if i]

if len(res) < 2:
return res[0], ""

# The last element found will be the description and the previous one the title.
return res[-1], ' -> '.join(res[:-1])
Binary file added images/docs/react.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions images/search-by-algolia-light-background.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit f346a10

Please sign in to comment.