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 @@ ...@@ -16,6 +16,8 @@
import codecs import codecs
import re import re
import os
import sys
import unittest import unittest
from collections import namedtuple from collections import namedtuple
...@@ -339,12 +341,16 @@ class ListCommandTest(CommandTest): ...@@ -339,12 +341,16 @@ class ListCommandTest(CommandTest):
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
@mock.patch('topydo.commands.ListCommand.get_terminal_size') @mock.patch('topydo.commands.ListCommand.get_terminal_size')
@mock.patch.dict(os.environ, {'PROMPT':'', 'PS1':''})
def test_list44(self, mock_terminal_size): def test_list44(self, mock_terminal_size):
""" """
Test 'N' parameter with output longer than available terminal lines. Test 'N' parameter with output longer than available terminal lines.
""" """
self.todolist = load_file_to_todolist("test/data/ListCommand_50_items.txt") 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 = ListCommand(["-N"], self.todolist, self.out, self.error)
command.execute() command.execute()
...@@ -353,11 +359,15 @@ class ListCommandTest(CommandTest): ...@@ -353,11 +359,15 @@ class ListCommandTest(CommandTest):
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
@mock.patch('topydo.commands.ListCommand.get_terminal_size') @mock.patch('topydo.commands.ListCommand.get_terminal_size')
@mock.patch.dict(os.environ, {'PROMPT':'', 'PS1':''})
def test_list45(self, mock_terminal_size): def test_list45(self, mock_terminal_size):
"""Test basic 'N' parameter with nine line terminal.""" """Test basic 'N' parameter with nine line terminal."""
# have 9 lines on the terminal will print 7 items and leave 2 lines # have 9 lines on the terminal will print 7 items and leave 2 lines
# for the next prompt # 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") self.todolist = load_file_to_todolist("test/data/ListCommand_50_items.txt")
command = ListCommand(["-N"], self.todolist, self.out, self.error) command = ListCommand(["-N"], self.todolist, self.out, self.error)
...@@ -367,6 +377,7 @@ class ListCommandTest(CommandTest): ...@@ -367,6 +377,7 @@ class ListCommandTest(CommandTest):
self.assertEqual(self.errors, "") self.assertEqual(self.errors, "")
@mock.patch('topydo.commands.ListCommand.get_terminal_size') @mock.patch('topydo.commands.ListCommand.get_terminal_size')
@mock.patch.dict(os.environ, {'PROMPT':'', 'PS1':''})
def test_list46(self, mock_terminal_size): def test_list46(self, mock_terminal_size):
"""Test basic 'N' parameter with zero height terminal.""" """Test basic 'N' parameter with zero height terminal."""
# we still print at least 1 item # we still print at least 1 item
...@@ -379,7 +390,26 @@ class ListCommandTest(CommandTest): ...@@ -379,7 +390,26 @@ class ListCommandTest(CommandTest):
self.assertEqual(self.output, "| 1| (A) item 1\n") self.assertEqual(self.output, "| 1| (A) item 1\n")
self.assertEqual(self.errors, "") 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 = ListCommand(["created:2015-11-05"], self.todolist, self.out, self.error)
command.execute() command.execute()
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # 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.Config import config
from topydo.lib.ExpressionCommand import ExpressionCommand from topydo.lib.ExpressionCommand import ExpressionCommand
from topydo.lib.Filter import InstanceFilter from topydo.lib.Filter import InstanceFilter
...@@ -73,7 +77,7 @@ class ListCommand(ExpressionCommand): ...@@ -73,7 +77,7 @@ class ListCommand(ExpressionCommand):
elif opt == '-N': elif opt == '-N':
# 2 lines are assumed to be taken up by printing the next prompt # 2 lines are assumed to be taken up by printing the next prompt
# display at least one item # display at least one item
self.limit = max(get_terminal_size().lines - 2, 1) self.limit = self._N_lines()
elif opt == '-n': elif opt == '-n':
try: try:
self.limit = int(value) self.limit = int(value)
...@@ -130,6 +134,36 @@ class ListCommand(ExpressionCommand): ...@@ -130,6 +134,36 @@ class ListCommand(ExpressionCommand):
self.out(self.printer.print_list(self._view().todos)) 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): def execute(self):
if not super().execute(): if not super().execute():
return False 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