Commit 1d19ce3d authored by Bram Schoenmakers's avatar Bram Schoenmakers

Merge pull request #118 from MinchinWeb/fix-102

Provides a smart way to determine the number 'top' lines
parents 14ab34d6 87b8b017
......@@ -16,6 +16,8 @@
import codecs
import re
import os
import sys
import unittest
from collections import namedtuple
......@@ -339,12 +341,16 @@ class ListCommandTest(CommandTest):
self.assertEqual(self.errors, "")
@mock.patch('topydo.commands.ListCommand.get_terminal_size')
@mock.patch.dict(os.environ, {'PROMPT':'', 'PS1':''})
def test_list44(self, mock_terminal_size):
"""
Test 'N' parameter with output longer than available terminal lines.
"""
self.todolist = load_file_to_todolist("test/data/ListCommand_50_items.txt")
mock_terminal_size.return_value = self.terminal_size(80, 23)
if "win32" in sys.platform:
mock_terminal_size.return_value = self.terminal_size(80, 23)
else:
mock_terminal_size.return_value = self.terminal_size(80, 22)
command = ListCommand(["-N"], self.todolist, self.out, self.error)
command.execute()
......@@ -353,11 +359,15 @@ class ListCommandTest(CommandTest):
self.assertEqual(self.errors, "")
@mock.patch('topydo.commands.ListCommand.get_terminal_size')
@mock.patch.dict(os.environ, {'PROMPT':'', 'PS1':''})
def test_list45(self, mock_terminal_size):
"""Test basic 'N' parameter with nine line terminal."""
# have 9 lines on the terminal will print 7 items and leave 2 lines
# for the next prompt
mock_terminal_size.return_value = self.terminal_size(100, 9)
if "win32" in sys.platform:
mock_terminal_size.return_value = self.terminal_size(100, 9)
else:
mock_terminal_size.return_value = self.terminal_size(100, 8)
self.todolist = load_file_to_todolist("test/data/ListCommand_50_items.txt")
command = ListCommand(["-N"], self.todolist, self.out, self.error)
......@@ -367,6 +377,7 @@ class ListCommandTest(CommandTest):
self.assertEqual(self.errors, "")
@mock.patch('topydo.commands.ListCommand.get_terminal_size')
@mock.patch.dict(os.environ, {'PROMPT':'', 'PS1':''})
def test_list46(self, mock_terminal_size):
"""Test basic 'N' parameter with zero height terminal."""
# we still print at least 1 item
......@@ -379,7 +390,26 @@ class ListCommandTest(CommandTest):
self.assertEqual(self.output, "| 1| (A) item 1\n")
self.assertEqual(self.errors, "")
def test_list47(self):
@mock.patch('topydo.commands.ListCommand.get_terminal_size')
@mock.patch.dict(os.environ, {'PROMPT':'$E[1;34m%username%@%computername%$E[0m$S$E[1;32m$P$E[0m$_$E[1;37m--$E[0m$S',
'PS1':'username@hostname\n--'})
def test_list47(self, mock_terminal_size):
"""
Test 'N' parameter with multiline prompt.
"""
self.todolist = load_file_to_todolist("test/data/ListCommand_50_items.txt")
if "win32" in sys.platform:
mock_terminal_size.return_value = self.terminal_size(80, 23)
else:
mock_terminal_size.return_value = self.terminal_size(80, 22)
command = ListCommand(["-N"], self.todolist, self.out, self.error)
command.execute()
self.assertEqual(self.output, "| 1| (A) item 1\n| 27| (A) item 27\n| 2| (B) item 2\n| 28| (B) item 28\n| 3| (C) item 3\n| 29| (C) item 29\n| 4| (D) item 4\n| 30| (D) item 30\n| 5| (E) item 5\n| 31| (E) item 31\n| 6| (F) item 6\n| 32| (F) item 32\n| 7| (G) item 7\n| 33| (G) item 33\n| 8| (H) item 8\n| 34| (H) item 34\n| 9| (I) item 9\n| 35| (I) item 35\n| 10| (J) item 10\n| 36| (J) item 36\n")
self.assertEqual(self.errors, "")
def test_list48(self):
command = ListCommand(["created:2015-11-05"], self.todolist, self.out, self.error)
command.execute()
......
......@@ -14,6 +14,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
import sys
import os
from topydo.lib.Config import config
from topydo.lib.ExpressionCommand import ExpressionCommand
from topydo.lib.Filter import InstanceFilter
......@@ -73,7 +77,7 @@ class ListCommand(ExpressionCommand):
elif opt == '-N':
# 2 lines are assumed to be taken up by printing the next prompt
# display at least one item
self.limit = max(get_terminal_size().lines - 2, 1)
self.limit = self._N_lines()
elif opt == '-n':
try:
self.limit = int(value)
......@@ -130,6 +134,36 @@ class ListCommand(ExpressionCommand):
self.out(self.printer.print_list(self._view().todos))
def _N_lines(self):
''' Determine how many lines to print, such that the number of items
displayed will fit on the terminal (i.e one 'screen-ful' of items)
This looks at the environmental prompt variable, and tries to determine
how many lines it takes up.
On Windows, it does this by looking for the '$_' sequence, which indicates
a new line, in the environmental variable PROMPT.
Otherwise, it looks for a newline ('\n') in the environmental variable
PS1.
'''
lines_in_prompt = 1 # prompt is assumed to take up one line, even
# without any newlines in it
if "win32" in sys.platform:
lines_in_prompt += 1 # Windows will typically print a free line after
# the program output
a = re.findall('\$_', os.getenv('PROMPT', ''))
lines_in_prompt += len(a)
else:
a = re.findall('\\n', os.getenv('PS1', ''))
lines_in_prompt += len(a)
n_lines = get_terminal_size().lines - lines_in_prompt
# print a minimum of one item
n_lines = max(n_lines, 1)
return n_lines
def execute(self):
if not super().execute():
return False
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment