Skip to content

Commit 00accc6

Browse files
committed
added vim bindings
1 parent 4841027 commit 00accc6

File tree

11 files changed

+126
-77
lines changed

11 files changed

+126
-77
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
CHANGELOG
22
=========
33

4-
v0.7.0
4+
v0.6.3
55
------
66

7-
- [ ] Vi keybindings
7+
- [x] Vi keybindings
88
- [x] Added option for smooth scroll
99
- [x] Preferences are now saved when updating the app
1010
- [x] Validators for smooth_scroll and preview_format

clid.egg-info/PKG-INFO

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Metadata-Version: 1.1
22
Name: clid
3-
Version: 0.6.2
3+
Version: 0.6.3
44
Summary: Command line app based on ncurses to edit ID3 tags of mp3 files
55
Home-page: https://github.com/GokulSoumya/clid
66
Author: Gokul

clid/NEW.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
v0.7.0
1+
v0.6.3
22
------
33

4-
- Vi keybindings
4+
- This is ;)
55
- Added option for smooth scroll
6+
- Vim keybindings(disabled by default)
67
- Preferences are now saved when updating the app
7-
- Validators for smooth_scroll and preview_format
8-
- Display a "What's New" Popup when app is run after an update
98

9+
10+
Note: Escape key tends to be a little slow, probably a bug in npyscreen, when in Vim mode

clid/base.py

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,87 @@ def change_setting(self, command_line, widget_proxy, live):
2222
"""Change a setting in the ini file"""
2323
pass # different for main and pref view; defined in respective files
2424

25+
2526
class ClidTextfield(npy.wgtextbox.Textfield):
27+
"""Normal textbox with home and end keys working"""
2628
def set_up_handlers(self):
2729
super().set_up_handlers()
2830
self.handlers[curses.KEY_END] = self.h_end
2931
self.handlers[curses.KEY_HOME] = self.h_home
3032

31-
def h_home(self, char):
33+
def h_home(self, input):
3234
self.cursor_position = 0
3335

34-
def h_end(self, char):
36+
def h_end(self, input):
3537
self.cursor_position = len(self.value)
3638

3739

40+
class ClidVimTextfield(ClidTextfield):
41+
"""Textfield class to be used as input boxes for tag fields when editing tags
42+
if vim mode is enabled.
43+
"""
44+
def __init__(self, *args, **kwargs):
45+
self.vim_handlers = {
46+
# movement
47+
'k': self.h_exit_up,
48+
'j': self.h_exit_down,
49+
'h': self.h_cursor_left,
50+
'l': self.h_cursor_right,
51+
curses.ascii.SP: self.h_cursor_right, # Space
52+
curses.KEY_BACKSPACE: self.h_cursor_left,
53+
# deletion
54+
'X': self.h_delete_left,
55+
'x': self.h_delete_right,
56+
# insert chars
57+
'i': self.h_vim_insert_mode,
58+
'a': self.h_vim_append_char,
59+
'A': self.h_vim_append_char_at_end,
60+
}
61+
super().__init__(*args, **kwargs) # set_up_handlers is called in __init__
62+
63+
def vim_add_handlers(self):
64+
"""Add vim keybindings to list of keybindings"""
65+
self.add_handlers(self.vim_handlers)
66+
67+
def vim_remove_handlers(self):
68+
"""Remove vim keybindings from list of keybindings"""
69+
for handler in self.vim_handlers:
70+
del self.handlers[handler]
71+
self.handlers[curses.KEY_BACKSPACE] = self.h_delete_left # else nothing will happen
72+
73+
def set_up_handlers(self):
74+
super().set_up_handlers()
75+
self.vim_add_handlers()
76+
self.handlers[curses.ascii.ESC] = self.h_vim_normal_mode # is a bit slow
77+
78+
def h_addch(self, input):
79+
if self.parent.in_insert_mode: # add characters only if in insert mode
80+
super().h_addch(input)
81+
82+
def h_vim_insert_mode(self, input):
83+
"""Enter insert mode"""
84+
self.parent.in_insert_mode = True
85+
self.vim_remove_handlers() # else `k`, j`, etc will not be added to text(will still act as keybindings)
86+
87+
def h_vim_normal_mode(self, input):
88+
"""Exit insert mode by pressing Esc"""
89+
self.parent.in_insert_mode = False
90+
self.cursor_position -= 1 # just like in vim
91+
self.vim_add_handlers() # removed earlier when going to insert mode
92+
93+
def h_vim_append_char(self, input):
94+
"""Append characters, like `a` in vim"""
95+
self.h_vim_insert_mode(input)
96+
self.cursor_position += 1
97+
98+
def h_vim_append_char_at_end(self, input):
99+
"""Add characters to the end of the line, like `A` in vim"""
100+
self.h_vim_insert_mode(input)
101+
self.h_end(input) # go to the end
102+
103+
class ClidVimTitleText(npy.TitleText):
104+
_entry_type = ClidVimTextfield
105+
38106
class ClidTitleText(npy.TitleText):
39107
_entry_type = ClidTextfield
40108

clid/config.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
music_dir = ~/Music
2-
smooth_scroll = true
32
preview_format = %a - %l - %n. %t
3+
smooth_scroll = true
4+
vim_mode = false

clid/database.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def make_strings(self):
125125
in the editing window
126126
"""
127127
# number of characters after which value of an option is displayed
128-
max_length = len(max(self.settings.keys())) + 3 # +3 is just to beautify
128+
max_length = len(max(self.settings.keys(), key=len)) + 3 # +3 is just to beautify
129129
self.disp_strings = []
130130

131131
for key, value in self.settings.items():
@@ -169,11 +169,15 @@ def __init__(self, main_form, settings):
169169
self.settings = settings
170170
self.main_form = main_form
171171
self.when_changed = {
172+
'vim_mode': self.vim_mode,
172173
'music_dir': self.music_dir,
173174
'smooth_scroll': self.smooth_scroll,
174175
'preview_format': self.preview_format
175176
}
176177

178+
def vim_mode(self):
179+
pass # doesn't need anything
180+
177181
def music_dir(self):
178182
self.main_form.value.load_files_and_set_values()
179183
self.main_form.load_files()

clid/editmeta.py

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,31 @@
88
import stagger
99
import npyscreen as npy
1010

11+
from . import base
1112
from . import _const
12-
from .base import ClidTitleText
1313

1414

1515
class EditMeta(npy.ActionFormV2):
16-
"""Edit the metadata of a track"""
16+
"""Edit the metadata of a track.
17+
18+
Attributes:
19+
in_insert_mode(bool):
20+
Used to decide whether the form is in insert/normal
21+
mode(if vi_keybindings are enabled). This is actually
22+
set as an attribute of the parent form so that all
23+
text boxes in the form are in the same mode.
24+
"""
25+
26+
def __init__(self, *args, **kwags):
27+
super().__init__(*args, **kwags)
28+
self.in_insert_mode = False
29+
1730
def create(self):
31+
# error if placed in __init__
32+
self.TEXTBOX = base.ClidVimTitleText \
33+
if self.parentApp.settings['vim_mode'] == 'true'\
34+
else base.ClidTitleText # vim keybindings if enabled
35+
1836
self.file = self.parentApp.current_file
1937
try:
2038
self.meta = stagger.read_tag(self.file)
@@ -27,23 +45,23 @@ def create(self):
2745
self.meta.album = '' # revert what was just done
2846
self.meta.write()
2947

30-
self.tit = self.add(ClidTitleText, name='Title', value=self.meta.title)
48+
self.tit = self.add(self.TEXTBOX, name='Title', value=self.meta.title)
3149
self.nextrely += 1
32-
self.alb = self.add(ClidTitleText, name='Album', value=self.meta.album)
50+
self.alb = self.add(self.TEXTBOX, name='Album', value=self.meta.album)
3351
self.nextrely += 1
34-
self.art = self.add(ClidTitleText, name='Artist', value=self.meta.artist)
52+
self.art = self.add(self.TEXTBOX, name='Artist', value=self.meta.artist)
3553
self.nextrely += 1
36-
self.ala = self.add(ClidTitleText, name='Album Artist', value=self.meta.album_artist)
54+
self.ala = self.add(self.TEXTBOX, name='Album Artist', value=self.meta.album_artist)
3755
self.nextrely += 2
3856

39-
self.gen = self.add(ClidTitleText, name='Genre', value=self.resolve_genre(self.meta.genre))
57+
self.gen = self.add(self.TEXTBOX, name='Genre', value=self.resolve_genre(self.meta.genre))
4058
self.nextrely += 1
41-
self.dat = self.add(ClidTitleText, name='Date/Year', value=self.meta.date)
59+
self.dat = self.add(self.TEXTBOX, name='Date/Year', value=self.meta.date)
4260
self.nextrely += 1
43-
self.tno = self.add(ClidTitleText, name='Track Number',
61+
self.tno = self.add(self.TEXTBOX, name='Track Number',
4462
value=str(self.meta.track if self.meta.track != 0 else ''))
4563
self.nextrely += 2
46-
self.com = self.add(ClidTitleText, name='Comment', value=self.meta.comment)
64+
self.com = self.add(self.TEXTBOX, name='Comment', value=self.meta.comment)
4765

4866
def set_up_handlers(self):
4967
super().set_up_handlers()

clid/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
__version__ = '0.6.2'
3+
__version__ = '0.6.3'
44

55
import os
66
import curses

clid/validators.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ class ValidationError(Exception):
1313
"""Raised when validation fails"""
1414
pass
1515

16+
17+
def true_or_false(test):
18+
"""Checks whether test is either 'true' or 'false'
19+
Used by other functions.
20+
"""
21+
if not(test == 'true' or test == 'false'):
22+
raise ValidationError('Acceptable values are "true" or "false"("' + test + '" is not valid)')
23+
24+
1625
def music_dir(test):
1726
"""Checks whether `test` exists and is a directory.
1827
Args:
@@ -41,15 +50,9 @@ def preview_format(test):
4150
raise ValidationError('"' + spec + '"' + ' is not a valid format specifier')
4251

4352

44-
def smooth_scroll(test):
45-
"""Checks whether test is either 'true' or 'false'"""
46-
if not(test == 'true' or test == 'false'):
47-
raise ValidationError('Sorry, but I can\'t make sense of ' + '"' + test + '"' + '; \
48-
acceptable values for smooth_scroll are "true" or "false"')
49-
50-
5153
VALIDATORS = {
5254
'music_dir': music_dir,
53-
'preview_format': preview_format,
54-
'smooth_scroll': smooth_scroll
55+
'vim_mode': true_or_false,
56+
'smooth_scroll': true_or_false,
57+
'preview_format': preview_format
5558
}

sdf

Lines changed: 0 additions & 44 deletions
This file was deleted.

0 commit comments

Comments
 (0)