Has anyone found a way to display a non-scrolling horizontal ruler at the top of the display when editing code? This would be very helpful when aligning try/except blocks. If it doesn’t exist it would be helpful to have it added in a future release.
Forum Archive
Horizontal ruler in code editor
Hey! I’m new, I joined the thing to learn how to hack on my iPad, but I don’t know how to do anything, can you teach me? 😕
@da44id This little (quick and dirty as usual for me 😀) creates a transparent
view at the top of the editor window.
If you prefer, you could put the ruler, as InputAccessoryView above the
standard keyboard, so you can scroll your script and see any line under
the ruler.
Comment the line
tv.superview().addSubview_(vo)
and uncomment the line
#tv.setInputAccessoryView_(vo) # attach accessory to textview
Editor font from Pythonista setting is extracted to know the width of a cell of the ruler.
You have to configure this script as a tool and run it in the editor tab.

Or

#coding: utf-8
import editor
from objc_util import *
import ui
NSUserDefaults = ObjCClass('NSUserDefaults')
@on_main_thread
def main():
ev = editor._get_editor_tab().editorView()
tv = ev.textView()
#print(dir(tv))
# get x-position and line height of Editor line
p = tv.positionFromPosition_offset_(tv.beginningOfDocument(), 0)
rge = tv.textRangeFromPosition_toPosition_(p,p)
rect = tv.firstRectForRange_(rge) # CGRect
x = rect.origin.x
y = rect.origin.y
h = rect.size.height
tv.setFrame_(CGRect(CGPoint(x,y), CGSize(tv.frame().size.width, tv.frame().size.height)))
# get font of Editor
defaults = NSUserDefaults.standardUserDefaults()
font_name = str(defaults.valueForKey_('EditorFontName'))
font_size = int(str(defaults.valueForKey_('EditorFontSize')))
# create ui.View for InputAccessoryView above keyboard
v = ui.ImageView()
w = ui.get_screen_size()[0] # width of keyboard = screen
h = font_size + 4
v.frame = (0,0,w,h)
v.border_width = 1
v.border_color = 'lightgray'
d = ui.measure_string('A',font=(font_name,font_size))[0]
with ui.ImageContext(w,h) as ctx:
n = 0
while x < w:
color = 'black' if n%10 == 0 else 'lightgray'
ui.set_color(color)
path = ui.Path()
path.move_to(x,0)
path.line_to(x,h)
path.stroke()
x = x + d
n += 1
ui_image = ctx.get_image()
v.image = ui_image
v.background_color = (1,1,1,0.2)
#v.background_color = (0,1,0,0.2)
v.touch_enabled = False
vo = ObjCInstance(v) # get ObjectiveC object of v
retain_global(v) # see https://forum.omz-software.com/topic/4653/button-action-not-called-when-view-is-added-to-native-view
#tv.superview().addSubview_(vo)
tv.setInputAccessoryView_(vo) # attach accessory to textview
#AAAAAAAAAAAAAAAAAAA
#23456789012345678901234567890123456789012345678901234567891#23456789012345678
if __name__ == '__main__':
main()
Sorry, little bug, when you change mode top/keyboard for testing, use this
and change kbd or top in pos = ...
#coding: utf-8
import editor
from objc_util import *
import ui
NSUserDefaults = ObjCClass('NSUserDefaults')
@on_main_thread
def main():
pos = 'kbd' # or 'top'
ev = editor._get_editor_tab().editorView()
tv = ev.textView()
#print(dir(tv))
# get x-position and line height of Editor line
p = tv.positionFromPosition_offset_(tv.beginningOfDocument(), 0)
rge = tv.textRangeFromPosition_toPosition_(p,p)
rect = tv.firstRectForRange_(rge) # CGRect
x = rect.origin.x
y = rect.origin.y
h = rect.size.height
if pos == 'top':
tv.setFrame_(CGRect(CGPoint(x,y), CGSize(tv.frame().size.width, tv.frame().size.height)))
# get font of Editor
defaults = NSUserDefaults.standardUserDefaults()
font_name = str(defaults.valueForKey_('EditorFontName'))
font_size = int(str(defaults.valueForKey_('EditorFontSize')))
# create ui.View for InputAccessoryView above keyboard
v = ui.ImageView()
w = ui.get_screen_size()[0] # width of keyboard = screen
h = font_size + 4
v.frame = (0,0,w,h)
v.border_width = 1
v.border_color = 'lightgray'
d = ui.measure_string('A',font=(font_name,font_size))[0]
with ui.ImageContext(w,h) as ctx:
n = 0
while x < w:
color = 'black' if n%10 == 0 else 'lightgray'
ui.set_color(color)
path = ui.Path()
path.move_to(x,0)
path.line_to(x,h)
path.stroke()
x = x + d
n += 1
ui_image = ctx.get_image()
v.image = ui_image
v.background_color = (1,1,1,0.2)
#v.background_color = (0,1,0,0.2)
v.touch_enabled = False
vo = ObjCInstance(v) # get ObjectiveC object of v
retain_global(v) # see https://forum.omz-software.com/topic/4653/button-action-not-called-when-view-is-added-to-native-view
if pos == 'top':
tv.superview().addSubview_(vo)
else:
tv.setInputAccessoryView_(vo) # attach accessory to textview
#AAAAAAAAAAAAAAAAAAA
#23456789012345678901234567890123456789012345678901234567891#23456789012345678
if __name__ == '__main__':
main()
With
h = font_size + 4
if pos == 'top':
tv.setFrame_(CGRect(CGPoint(x,0), CGSize(tv.frame().size.width, tv.frame().size.height)))
h = tv.frame().size.height
you could even have a ruler for the entire height

@da44id Not what you wanted?