-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
yotsuyanagi
committed
Feb 19, 2016
0 parents
commit bb2b780
Showing
5 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# General | ||
tmp | ||
temp | ||
#* | ||
.#* | ||
|
||
# Editor | ||
*~ | ||
*.orig | ||
*.swp | ||
|
||
# Python | ||
*.pyc | ||
*.pyo | ||
|
||
# Windows | ||
Thumbs.db | ||
|
||
# Eclipse | ||
.project | ||
|
||
# Pydev | ||
.pydevproject | ||
|
||
# Mac | ||
.DS_Store | ||
|
||
# Xcode | ||
build/ | ||
*.pbxuser | ||
!default.pbxuser | ||
*.mode1v3 | ||
!default.mode1v3 | ||
*.mode2v3 | ||
!default.mode2v3 | ||
*.perspectivev3 | ||
!default.perspectivev3 | ||
xcuserdata | ||
*.xccheckout | ||
*.moved-aside | ||
DerivedData | ||
*.hmap | ||
*.ipa | ||
*.xcuserstate | ||
|
||
|
||
# CocoaPod | ||
Pods/* | ||
Podfile.lock | ||
|
||
# JetBrains | ||
.idea | ||
|
||
# if required | ||
# data/* | ||
# config/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
~~~~~~~ | ||
jj-menu | ||
~~~~~~~ | ||
|
||
Simple CLI Menu | ||
|
||
|
||
Install | ||
------- | ||
:: | ||
|
||
$ sudo pip install git+https://github.com/junion-org/pip_github_test.git | ||
|
||
|
||
Setup | ||
----- | ||
|
||
Create jjfile.py into any directory. | ||
|
||
:: | ||
|
||
menu = [ | ||
('list python processes', 'ps -eafw|grep python'), | ||
('move tmp', 'cd /tmp/'), | ||
('list dirs', ['ls .', 'ls ..', 'ls ../..']), | ||
] | ||
|
||
Run | ||
--- | ||
|
||
:: | ||
|
||
$ jj | ||
|
||
|
||
Key binds | ||
--------- | ||
|
||
ESC: Exit | ||
Q: Exit | ||
k: Up | ||
j: Down |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/usr/bin/env python | ||
# coding: utf-8 | ||
|
||
__author__ = 'ytyng' | ||
__version__ = '0.0.1' | ||
__license__ = 'MIT' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
#!/usr/bin/env python | ||
# -*- coding:utf-8 -*- | ||
|
||
from __future__ import unicode_literals, print_function | ||
import os | ||
import sys | ||
import locale | ||
import curses | ||
import _curses | ||
import six | ||
|
||
# 文字化け対応 | ||
locale.setlocale(locale.LC_ALL, '') | ||
|
||
COLOR_ACTIVE = 1 | ||
|
||
result_filename = '/tmp/_jj_result' | ||
|
||
|
||
class MenuFileNotFound(Exception): | ||
pass | ||
|
||
|
||
def initialize_colors(): | ||
curses.use_default_colors() | ||
curses.init_pair(COLOR_ACTIVE, curses.COLOR_BLACK, curses.COLOR_WHITE) | ||
|
||
|
||
def find_menu_file_path(cwd): | ||
paths = [ | ||
os.path.join(cwd, 'jjfile'), | ||
os.path.join(cwd, 'jjfile.py'), ] | ||
for p in paths: | ||
if os.path.exists(p): | ||
return p | ||
parent_dir = os.path.dirname(cwd) | ||
if parent_dir == cwd: | ||
raise MenuFileNotFound() | ||
else: | ||
return find_menu_file_path(parent_dir) | ||
|
||
|
||
def import_menu_settings(): | ||
menu_file_path = find_menu_file_path(os.getcwd()) | ||
|
||
importer = __import__ | ||
# Get directory and fabfile name | ||
dir_name, file_name = os.path.split(menu_file_path) | ||
if dir_name not in sys.path: | ||
sys.path.insert(0, dir_name) | ||
imported = importer(os.path.splitext(file_name)[0]) | ||
return imported | ||
|
||
|
||
def get_menu(): | ||
def _get_menus(): | ||
""" | ||
メニュー項目1つなら同じものに展開 | ||
""" | ||
menus = getattr(import_menu_settings(), 'menu') | ||
for m in menus: | ||
if isinstance(m, str): | ||
yield (m, m) | ||
elif len(m) >= 2: | ||
if isinstance(m[1], (list, tuple)): | ||
yield (m[0], ";".join(m[1])) | ||
else: | ||
yield m | ||
|
||
return list(_get_menus()) | ||
|
||
|
||
def window_addstr(window, y, x, message, color=None): | ||
""" | ||
python 2, 3 multi-bytes compatible | ||
""" | ||
if six.PY2: | ||
new_message = message.encode('utf-8') | ||
else: | ||
new_message = message | ||
args = [y, x, new_message] | ||
if color is not None: | ||
args.append(color) | ||
try: | ||
window.addstr(*args) | ||
except _curses.error: | ||
pass | ||
# print(e) | ||
|
||
|
||
class Launcher(object): | ||
def __init__(self, stdscr): | ||
stdscr.refresh() # なにより先にまず1回リフレッシュ | ||
self.stdscr = stdscr | ||
self.max_y, self.max_x = stdscr.getmaxyx() | ||
self.pos_y = 0 | ||
self.menu = get_menu() | ||
self.init_outfile() | ||
|
||
def render(self): | ||
win = curses.newwin( | ||
len(self.menu), self.max_x, 0, 0) | ||
for y, item in enumerate(self.menu): | ||
item_name_str = item[0] | ||
if y == self.pos_y: | ||
window_addstr( | ||
win, y, 0, '*> {}'.format(item_name_str), | ||
curses.color_pair(COLOR_ACTIVE)) | ||
else: | ||
window_addstr( | ||
win, y, 0, ' {}'.format(item_name_str)) | ||
win.refresh() | ||
# win.refresh(0, 0, 0, 0, len(MENU), self.max_x) | ||
|
||
help_win = curses.newwin(1, self.max_x, self.max_y - 1, 0) | ||
message = '$ {}'.format(self.menu[self.pos_y][1]) | ||
window_addstr( | ||
help_win, 0, 0, message[:self.max_x - 1], | ||
curses.color_pair(COLOR_ACTIVE)) | ||
help_win.refresh() | ||
|
||
def debug(self, message): | ||
""" | ||
簡易デバッグ | ||
""" | ||
win = curses.newwin(1, 10, self.max_y - 2, self.max_x - 10) | ||
window_addstr(win, 0, 0, message[:10]) | ||
win.refresh() | ||
|
||
def serve(self): | ||
while True: | ||
|
||
self.render() | ||
|
||
# キー入力待機 | ||
c = self.stdscr.getch() | ||
|
||
if c in (14, 106, 258): # ↓ | ||
if self.pos_y < len(self.menu) - 1: | ||
self.pos_y += 1 | ||
|
||
elif c in (16, 107, 259): # ↑ | ||
if self.pos_y > 0: | ||
self.pos_y -= 1 | ||
|
||
elif c in (2, 104, 260): # ← | ||
pass | ||
|
||
elif c in (6, 108, 261): # → | ||
pass | ||
elif c in (113, 27): # Q, Esc | ||
raise KeyboardInterrupt() | ||
elif c == 10: | ||
# 決定 | ||
with open(result_filename, 'w') as fp: | ||
fp.write(self.menu[self.pos_y][1]) | ||
return self.menu[self.pos_y] | ||
else: | ||
self.debug('{}'.format(c)) | ||
|
||
def init_outfile(self): | ||
with open(result_filename, 'w') as fp: | ||
fp.write('') | ||
|
||
|
||
def launch(stdscr): | ||
initialize_colors() | ||
_curses.curs_set(0) | ||
# 画面サイズ取得 | ||
launcher = Launcher(stdscr) | ||
|
||
selected = launcher.serve() | ||
return selected | ||
|
||
|
||
def main(): | ||
try: | ||
selected = curses.wrapper(launch) | ||
print('$ {}'.format(selected[1])) | ||
except KeyboardInterrupt: | ||
exit(1) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#!/usr/bin/env python | ||
# coding: utf-8 | ||
from setuptools import setup, find_packages | ||
from jj_menu import __author__, __version__, __license__ | ||
|
||
install_requires=['curses', 'six'] | ||
|
||
setup( | ||
name='jj-menu', | ||
version=__version__, | ||
description='Simple CLI Menu', | ||
license=__license__, | ||
author=__author__, | ||
author_email='[email protected]', | ||
url='https://github.com/jytyng/jj-menu.git', | ||
keywords='CLI Menu, Python', | ||
packages=find_packages(), | ||
install_requires=[], | ||
) |