Skip to content

Instantly share code, notes, and snippets.

@boredzo
Last active August 29, 2015 14:03
Show Gist options
  • Save boredzo/40529c60351f62d23ed2 to your computer and use it in GitHub Desktop.
Save boredzo/40529c60351f62d23ed2 to your computer and use it in GitHub Desktop.
indexheaders/findheader

indexheaders/findheader

Ever wish you could do something like view $(findheader signal.h)—and have it be fast? Now you can.

(open -h is one alternative, but that opens it in Xcode, rather than a terminal-based or other editor.)

Basically, it's like “Open Quickly” for the command line.

Installation

Place the .py file in your ~/bin (or other such directory of your choice) under two names (by hard-linking or copying):

  • indexheaders (note plural)
  • findheader

Don't forget to chmod +x it (or the copies, if you copy instead of link).

Usage

First, run indexheaders. This will generate an index of pathnames of all of your latest-OS-X-SDK (or, if Xcode is not installed, system) headers, stored at ~/Library/Caches/Header Index.

Subsequently, you can run findheader <header-name> to find the location of a header by name.

Advanced usage

indexheaders supports a --xcode=<path> if you'd like it to look in a specific Xcode (such as a beta).

Currently, it always uses the latest OS X SDK in that Xcode. There's no provision to choose another platform (iPhoneOS) or another SDK version at this time.

If you really want to index system headers rather than SDK headers, --xcode=/ works.

Quirks

This is really old code, updated only to be aware of Xcode SDKs. For example, it doesn't use optparse, much less argparse.

Despite the name and purpose, it indexes all files, not only headers. This may be a virtue: You could probably find certain frameworks' internal PNG or ICNS files, for example.

Also, despite the name, it does not index file contents.

#!/usr/bin/env python
import os
from os import path
#defaults.
startdirs = ['/System/Library/Frameworks', '/Library/Frameworks', '~/Library/Frameworks', '/Network/Library/Frameworks', '/usr/include', '/usr/local/include']
indexpath = "~/Library/Caches/Header Index" #path to the index file.
verbose = False
#do not edit below this point.
indexpath = path.expanduser(indexpath)
startdirs = [path.expanduser(pn) for pn in startdirs]
def parse_SDK_name(sdkname):
"SDK filename -> tuple of strings and ints (/[0-9]+/ -> int)"
import re
slices = []
slice_start = 0
slice_end = 0
for match in re.finditer('[0-9]+', sdkname):
slice_end = match.start()
slices.append(sdkname[slice_start:slice_end])
slices.append(int(match.group(0)))
slice_start = match.end()
else:
slices.append(sdkname[slice_start:])
return tuple(slices)
def reassemble_SDK_name(sdk_slices):
from itertools import imap
return ''.join(imap(str, sdk_slices))
def find_latest_SDK(xcode=None, platform=None):
if platform is None:
platform = find_OSX_platform(xcode)
if verbose:
print 'Searching for SDKs in platform at', platform, '...',
if platform is None:
if verbose: print
return None
sdk_dir = path.join(platform, 'Developer', 'SDKs')
sdks = map(parse_SDK_name, os.listdir(sdk_dir))
sdks.sort()
sdks = map(reassemble_SDK_name, sdks)
sdkname = sdks[-1]
sdkpath = path.join(sdk_dir, sdkname)
if verbose:
print sdkpath
return sdkpath
def find_OSX_platform(xcode=None):
if verbose:
print 'Searching for OS X platform in Xcode at', xcode, '...',
if xcode is not None:
developer_dir = path.join(xcode, 'Contents', 'Developer')
else:
import subprocess
xcode_select = subprocess.Popen(['xcode-select', '-p'], stdout=subprocess.PIPE)
developer_dir = xcode_select.stdout.read().rstrip('\n')
if developer_dir is None:
return None
platform = path.join(developer_dir, 'Platforms', 'MacOSX.platform')
if verbose:
print platform
return platform \
if path.exists(platform) \
else None
def index(startdirs, indexfile, xcode=None):
"print a list of all the header (.h) files in every directory and subdirectory of startdirs, into the indexfile (a flob)."
sdkroot = find_latest_SDK(xcode)
if sdkroot is not None:
print "Indexing headers in %s..." % (sdkroot,),
else:
print "Indexing headers...",
sys.stdout.flush()
i = 0
startdirs = (os.path.join(sdkroot, dir.lstrip('/')) if sdkroot else dir for dir in startdirs)
if verbose:
print
startdirs = list(startdirs)
print 'Top-level directories:', startdirs
for sd in startdirs:
if verbose:
print 'Indexing', sd, '...',
sys.stdout.flush()
j = 0
dirs = os.walk(sd)
for dir, subdirs, files in dirs:
#unused: subdirs
for filename in files:
print >>indexfile, path.join(dir, filename)
i += 1
j += 1
if verbose:
print j, "files found in directory."
print i, "files found."
def search(headername, indexpath = indexpath):
assert headername is not None
# if not headername.endswith('.h'):
# headername += '.h\n'
# else:
# headername += '\n'
headername = '/' + headername + '\n'
if not path.isfile(indexpath):
f = file(indexpath, 'w')
index(startdirs, f)
f.close()
paths = file(indexpath, 'r')
if verbose:
print "Searching for", repr(headername), "..."
for pathname in paths:
if pathname.endswith(headername):
sys.stdout.write(pathname)
if verbose:
print "Done"
paths.close()
def main(argv):
global indexpath, verbose
indexheaders_usage = "usage: indexheaders [-n|--dry-run] [-v|--verbose|-q|--quiet] [--xcode=path]"
findheader_usage = "usage: findheader [-c] [-v|--verbose|-q|--quiet] one-or-more-headers"
progname = path.basename(argv[0])
if progname == 'findheader':
usage = findheader_usage
if len(argv) == 1 or '-h' in argv or '?' in argv or '--help' in argv:
print usage
else:
for i, headername in enumerate(sys.argv[1:]):
if headername == '-c':
#index
newargv = ['indexheaders']
main(newargv)
break
elif headername == '-v' or headername == '--verbose':
verbose = True
elif headername == '-q' or headername == '--quiet':
verbose = False
else:
search(headername, indexpath)
elif progname == 'indexheaders':
usage = indexheaders_usage
xcode = None #auto-detect using xcode-select -p
if len(argv) == 1 or '-h' in argv or '?' in argv or '--help' in argv:
print usage
else:
for headername in argv[1:]:
if headername.startswith('--xcode='):
xcode = headername[len('--xcode='):]
elif headername == '-n' or headername == '--dry-run':
indexpath = '/dev/null'
elif headername == '-v' or headername == '--verbose':
verbose = True
elif headername == '-q' or headername == '--quiet':
verbose = False
else:
sys.exit(usage)
f = file(indexpath, 'w')
index(startdirs, f, xcode=xcode)
f.close()
else:
print >>sys.stderr, indexheaders_usage
print >>sys.stderr, findheader_usage
if __name__ == '__main__':
import sys
main(sys.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment