Repository: kovidgoyal/kitty

Issue:
Vertically align content to top instead of center
As reported in #416, when the window height is not a multiple of cell height the content is centered veritcally, and thus produces a row of empty pixels at the top and bottom.

I think it would be better if it were aligned to the top, and the empty pixels were all at the bottom. This seems to be how other terminals handle this.


Discussion:
I prefer it aligned in the center. That said, I wont refuse a PR for an option to change its alignment, but it is not something I am interested in implementing myself.
Got it. Would you be able to point out where I'd need to look if I wanted to implement this?
IIRC layout.py
It would be good if there was an option to configure aligning to top or centre
iterm2 aligns to the top. I definitely think it looks better, because every non terminal window will align to the top. The user is more likely to look at the top of the screen than the bottom of the screen anyway. Aligning to the centre looks very very strange

<img width="840" alt="screen shot 2018-08-19 at 3 50 57 pm" src="https://user-images.githubusercontent.com/17482349/44305269-c0025d80-a3c7-11e8-8ec2-5d7fb9267841.png">

Here's a patch that removes the padding from the top and left:

```diff
diff --git a/kitty/layout.py b/kitty/layout.py
index cf6c1a16..b93f5c79 100644
--- a/kitty/layout.py
+++ b/kitty/layout.py
@@ -85,8 +85,8 @@ def window_geometry(xstart, xnum, ystart, ynum):
 
 
 def layout_single_window(xdecoration_pairs, ydecoration_pairs):
-    xstart, xnum = next(layout_dimension(central.left, central.width, cell_width, xdecoration_pairs))
-    ystart, ynum = next(layout_dimension(central.top, central.height, cell_height, ydecoration_pairs))
+    xstart, xnum = next(layout_dimension(central.left, central.width, cell_width, xdecoration_pairs, left_align=True))
+    ystart, ynum = next(layout_dimension(central.top, central.height, cell_height, ydecoration_pairs, left_align=True))
     return window_geometry(xstart, xnum, ystart, ynum)
 
```
@copy Thanks for investigating this! Could you submit a pr? I think it is a bit too inconvenient for most people to sort out compiling the terminal from source

Resolving patch:
diff --git a/kitty/boss.py b/kitty/boss.py
--- a/kitty/boss.py
+++ b/kitty/boss.py
@@ -28,7 +28,7 @@
     toggle_maximized
 )
 from .keys import get_shortcut, shortcut_matches
-from .layout import set_draw_borders_options
+from .layout import set_layout_options
 from .remote_control import handle_cmd
 from .rgb import Color, color_from_int
 from .session import create_sessions
@@ -105,7 +105,7 @@ def __call__(self, *a):
 class Boss:
 
     def __init__(self, os_window_id, opts, args, cached_values, new_os_window_trigger):
-        set_draw_borders_options(opts)
+        set_layout_options(opts)
         self.clipboard_buffers = {}
         self.update_check_process = None
         self.window_id_map = WeakValueDictionary()
diff --git a/kitty/config_data.py b/kitty/config_data.py
--- a/kitty/config_data.py
+++ b/kitty/config_data.py
@@ -558,6 +558,10 @@ def to_layout_names(raw):
 startup layout. For a list of available layouts, see the :ref:`layouts`.
 '''))
 
+o('align_top_left', False, long_text=_('''
+Align terminal to the top left corner, i.e. put padding on the bottom and right. Default is centered.
+'''))
+
 o('window_resize_step_cells', 2, option_type=positive_int, long_text=_('''
 The step size (in units of cell width/cell height) to use when resizing
 windows. The cells value is used for horizontal resizing and the lines value
diff --git a/kitty/layout.py b/kitty/layout.py
--- a/kitty/layout.py
+++ b/kitty/layout.py
@@ -18,6 +18,7 @@
 no_borders = False, False, False, False
 draw_minimal_borders = False
 draw_active_borders = True
+align_top_left = False
 
 
 def idx_for_id(win_id, windows):
@@ -26,10 +27,11 @@ def idx_for_id(win_id, windows):
             return i
 
 
-def set_draw_borders_options(opts):
-    global draw_minimal_borders, draw_active_borders
+def set_layout_options(opts):
+    global draw_minimal_borders, draw_active_borders, align_top_left
     draw_minimal_borders = opts.draw_minimal_borders and opts.window_margin_width == 0
     draw_active_borders = opts.active_border_color is not None
+    align_top_left = bool(opts.align_top_left)
 
 
 def layout_dimension(start_at, length, cell_length, decoration_pairs, left_align=False, bias=None):
@@ -86,9 +88,9 @@ def window_geometry(xstart, xnum, ystart, ynum):
     return WindowGeometry(left=xstart, top=ystart, xnum=xnum, ynum=ynum, right=xstart + cell_width * xnum, bottom=ystart + cell_height * ynum)
 
 
-def layout_single_window(xdecoration_pairs, ydecoration_pairs):
-    xstart, xnum = next(layout_dimension(central.left, central.width, cell_width, xdecoration_pairs))
-    ystart, ynum = next(layout_dimension(central.top, central.height, cell_height, ydecoration_pairs))
+def layout_single_window(xdecoration_pairs, ydecoration_pairs, left_align=False):
+    xstart, xnum = next(layout_dimension(central.left, central.width, cell_width, xdecoration_pairs, left_align=align_top_left))
+    ystart, ynum = next(layout_dimension(central.top, central.height, cell_height, ydecoration_pairs, left_align=align_top_left))
     return window_geometry(xstart, xnum, ystart, ynum)
 
 
@@ -368,12 +370,12 @@ def layout_single_window(self, w):
     def xlayout(self, num, bias=None):
         decoration = self.margin_width + self.border_width + self.padding_width
         decoration_pairs = tuple(repeat((decoration, decoration), num))
-        return layout_dimension(central.left, central.width, cell_width, decoration_pairs, bias=bias)
+        return layout_dimension(central.left, central.width, cell_width, decoration_pairs, bias=bias, left_align=align_top_left)
 
     def ylayout(self, num, left_align=True, bias=None):
         decoration = self.margin_width + self.border_width + self.padding_width
         decoration_pairs = tuple(repeat((decoration, decoration), num))
-        return layout_dimension(central.top, central.height, cell_height, decoration_pairs, bias=bias)
+        return layout_dimension(central.top, central.height, cell_height, decoration_pairs, bias=bias, left_align=align_top_left)
 
     def simple_blank_rects(self, first_window, last_window):
         br = self.blank_rects
@@ -417,7 +419,7 @@ class Stack(Layout):  # {{{
     def do_layout(self, windows, active_window_idx):
         mw = self.margin_width if self.single_window_margin_width < 0 else self.single_window_margin_width
         decoration_pairs = ((mw + self.padding_width, mw + self.padding_width),)
-        wg = layout_single_window(decoration_pairs, decoration_pairs)
+        wg = layout_single_window(decoration_pairs, decoration_pairs, left_align=align_top_left)
         for i, w in enumerate(windows):
             w.set_geometry(i, wg)
             if w.is_visible_in_layout:


Test patch: