├── .gitignore ├── LICENSE ├── README.md ├── found └── found-func.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Cheng Lian. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | `Found` is a simple wrapper script over `locate` and `xdg-open`. It searches files with `locate` and let you to choose the file to open interactively. 4 | 5 | ## Usage 6 | 7 | Check out `found` and put the script into one of your `PATH` directories. Call `found` with some terms that appears in the target file name. For example: 8 | 9 | $ found lamport pdf 10 | 11 | Sample output: 12 | 13 | [1] 568998.Lamport - 1998 - The part-time parliament.pdf.xml 14 | [2] 595489.Lamport - 1998 - The part-time parliament-annotated.pdf.xml 15 | [3] lamport-paxos.pdf 16 | [4] Cheap paxos - Lamport, Massa - 2004.pdf 17 | [5] Consensus on transaction commit - Gray, Lamport - 2006.pdf 18 | [6] Fast Paxos - Lamport - 2006.pdf 19 | [7] LATEX A Document Preparation System User's Guide and Reference Manual - Lamport - 1986.pdf 20 | [8] LaTeX2e The macro package for TeX - Lamport - 1994.pdf 21 | [9] Paxos made simple - Lamport - 2001.pdf 22 | [10] Solved problems, unsolved problems and non-problems in concurrency - Lamport - 1985.pdf 23 | [11] Specifying systems The TLA language and tools for hardware and software engineers - Lamport - 2002.pdf 24 | [12] The Byzantine Generals Problem - Lamport, Shostak, Pease - 1982.pdf 25 | [13] The part-time parliament - Lamport - 1998.pdf 26 | [14] Time, clocks, and the ordering of events in a distributed system - Lamport - 1978.pdf 27 | [15] Using Time Instead of Timeout for Fault-Tolerant Distributed Systems. - Lamport - 1984.pdf 28 | [16] Vertical paxos and primary-backup replication - Lamport, Malkhi, Zhou - 2009.pdf 29 | 30 | Which file to open: 31 | 32 | Then you may choose the file to open. If there's only one match, the file will be opened directly. 33 | 34 | ## Behind the scene 35 | 36 | `Found` is deadly simple. First, it joins all the terms from the command line into a `locate` query, e.g.: 37 | 38 | $ found lamport pdf 39 | 40 | turns into: 41 | 42 | $ locate -b -i "*lamport*pdf*" 43 | 44 | After you specified the file to open, `found` will call `xdg-open` to open the file with the most appropriate program. 45 | -------------------------------------------------------------------------------- /found: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | from subprocess import call, check_output, Popen 5 | from os.path import isdir 6 | from os import system 7 | 8 | import argparse 9 | import sys 10 | 11 | 12 | def open_file(filepath): 13 | call(['xdg-open', filepath]) 14 | 15 | 16 | def copy_to_xclip(filepath): 17 | system('echo -n %s | xclip' % filepath) 18 | 19 | 20 | def copy_to_xsel(filepath): 21 | system('echo -n %s | xsel' % filepath) 22 | 23 | 24 | def write_path(filepath): 25 | with open(args.write, 'w') as out: 26 | out.write(filepath) 27 | 28 | 29 | def locate(terms, is_directory, case_sensitive): 30 | options = [] 31 | 32 | pattern = '*' + '*'.join(terms) 33 | 34 | if not is_directory: 35 | pattern += '*' 36 | options.append('--basename') 37 | 38 | if not case_sensitive: 39 | options.append('--ignore-case') 40 | 41 | cmd = ['locate'] + options + [pattern] 42 | 43 | try: 44 | items = check_output(cmd)[:-1].split('\n') 45 | except: 46 | items = [] 47 | 48 | return [_ for _ in items if isdir(_)] if is_directory else items 49 | 50 | 51 | def show_candidates(items): 52 | try: 53 | from termcolor import colored 54 | 55 | for i in range(1, len(items) + 1): 56 | print(colored('[%d] ' % i, 'yellow', attrs=['bold']), end='') 57 | print(items[i - 1]) 58 | 59 | except: 60 | for i in range(1, len(items) + 1): 61 | print('[%d]' % i, items[i - 1]) 62 | 63 | 64 | def select_item(items, action): 65 | if len(items) == 1: 66 | action(items[0]) 67 | else: 68 | show_candidates(items) 69 | item_no = int(raw_input("\nChoose one file to open: ")) 70 | action(items[item_no - 1]) 71 | 72 | 73 | if __name__ == '__main__': 74 | parser = argparse.ArgumentParser(description='Find and open files easily.') 75 | 76 | parser.add_argument('terms', 77 | metavar='term', 78 | nargs='+', 79 | help='The terms to search with') 80 | 81 | parser.add_argument('-d', '--directory', 82 | action='store_true', 83 | help='Search for directories instead of files') 84 | 85 | parser.add_argument('-c', '--case-sensitive', 86 | action='store_true', 87 | help='Enable case sensitive search') 88 | 89 | group = parser.add_mutually_exclusive_group() 90 | 91 | group.add_argument('-x', '--xclip', 92 | action='store_true', 93 | help='Copy full path of seleted item to X clipboard') 94 | 95 | group.add_argument('-s', '--xsel', 96 | action='store_true', 97 | help='Copy full path of seleted item to X selection') 98 | 99 | group.add_argument('-w', '--write', 100 | metavar='file', 101 | action='store', 102 | help='Write full path of seleted item to `file\'') 103 | 104 | args = parser.parse_args() 105 | items = locate(args.terms, args.directory, args.case_sensitive) 106 | 107 | if len(items) == 0: 108 | print("File(s) not found.") 109 | sys.exit(1) 110 | 111 | try: 112 | if args.xclip: 113 | action = copy_to_xclip 114 | elif args.xsel: 115 | action = copy_to_xsel 116 | elif args.write != None: 117 | action = write_path 118 | else: 119 | action = open_file 120 | 121 | select_item(items, action) 122 | except: 123 | pass 124 | -------------------------------------------------------------------------------- /found-func.sh: -------------------------------------------------------------------------------- 1 | function found_cd() { 2 | if [ $# -eq 0 ]; then 3 | cd ~ 4 | else 5 | tmpfile="/tmp/found-cd-$$" 6 | found -d -w $tmpfile $@ 7 | 8 | if [ $? -eq 0 ]; then 9 | cd `cat $tmpfile` 10 | rm -f $tmpfile 11 | fi 12 | fi 13 | } 14 | 15 | alias fcd=found_cd 16 | 17 | # vim:ft=sh 18 | --------------------------------------------------------------------------------