• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Widgets for Curses-based CLI."""
16from __future__ import absolute_import
17from __future__ import division
18from __future__ import print_function
19
20from tensorflow.python.debug.cli import debugger_cli_common
21
22
23RL = debugger_cli_common.RichLine
24
25
26class NavigationHistoryItem(object):
27  """Individual item in navigation history."""
28
29  def __init__(self, command, screen_output, scroll_position):
30    """Constructor of NavigationHistoryItem.
31
32    Args:
33      command: (`str`) the command line text.
34      screen_output: the screen output of the command.
35      scroll_position: (`int`) scroll position in the screen output.
36    """
37    self.command = command
38    self.screen_output = screen_output
39    self.scroll_position = scroll_position
40
41
42class CursesNavigationHistory(object):
43  """Navigation history containing commands, outputs and scroll info."""
44
45  BACK_ARROW_TEXT = "<--"
46  FORWARD_ARROW_TEXT = "-->"
47
48  def __init__(self, capacity):
49    """Constructor of CursesNavigationHistory.
50
51    Args:
52      capacity: (`int`) How many items this object can hold. Each item consists
53        of a command stirng, an output RichTextLines object and a scroll
54        position.
55
56    Raises:
57      ValueError: If capacity is not a positive number.
58    """
59    if capacity <= 0:
60      raise ValueError("In valid capacity value: %d" % capacity)
61
62    self._capacity = capacity
63    self._items = []
64    self._pointer = -1
65
66  def add_item(self, command, screen_output, scroll_position):
67    """Add an item to the navigation histoyr.
68
69    Args:
70      command: command line text.
71      screen_output: screen output produced for the command.
72      scroll_position: (`int`) scroll position in the screen output.
73    """
74    if self._pointer + 1 < len(self._items):
75      self._items = self._items[:self._pointer + 1]
76    self._items.append(
77        NavigationHistoryItem(command, screen_output, scroll_position))
78    if len(self._items) > self._capacity:
79      self._items = self._items[-self._capacity:]
80    self._pointer = len(self._items) - 1
81
82  def update_scroll_position(self, new_scroll_position):
83    """Update the scroll position of the currently-pointed-to history item.
84
85    Args:
86      new_scroll_position: (`int`) new scroll-position value.
87
88    Raises:
89      ValueError: If the history is empty.
90    """
91    if not self._items:
92      raise ValueError("Empty navigation history")
93    self._items[self._pointer].scroll_position = new_scroll_position
94
95  def size(self):
96    return len(self._items)
97
98  def pointer(self):
99    return self._pointer
100
101  def go_back(self):
102    """Go back one place in the history, if possible.
103
104    Decrease the pointer value by 1, if possible. Otherwise, the pointer value
105    will be unchanged.
106
107    Returns:
108      The updated pointer value.
109
110    Raises:
111      ValueError: If history is empty.
112    """
113    if not self._items:
114      raise ValueError("Empty navigation history")
115
116    if self.can_go_back():
117      self._pointer -= 1
118    return self._items[self._pointer]
119
120  def go_forward(self):
121    """Go forward one place in the history, if possible.
122
123    Increase the pointer value by 1, if possible. Otherwise, the pointer value
124    will be unchanged.
125
126    Returns:
127      The updated pointer value.
128
129    Raises:
130      ValueError: If history is empty.
131    """
132    if not self._items:
133      raise ValueError("Empty navigation history")
134
135    if self.can_go_forward():
136      self._pointer += 1
137    return self._items[self._pointer]
138
139  def can_go_back(self):
140    """Test whether client can go back one place.
141
142    Returns:
143      (`bool`) Whether going back one place is possible.
144    """
145    return self._pointer >= 1
146
147  def can_go_forward(self):
148    """Test whether client can go forward one place.
149
150    Returns:
151      (`bool`) Whether going back one place is possible.
152    """
153    return self._pointer + 1 < len(self._items)
154
155  def render(self,
156             max_length,
157             backward_command,
158             forward_command,
159             latest_command_attribute="black_on_white",
160             old_command_attribute="magenta_on_white"):
161    """Render the rich text content of the single-line navigation bar.
162
163    Args:
164      max_length: (`int`) Maximum length of the navigation bar, in characters.
165      backward_command: (`str`) command for going backward. Used to construct
166        the shortcut menu item.
167      forward_command: (`str`) command for going forward. Used to construct the
168        shortcut menu item.
169       latest_command_attribute: font attribute for lastest command.
170       old_command_attribute: font attribute for old (non-latest) command.
171
172    Returns:
173      (`debugger_cli_common.RichTextLines`) the navigation bar text with
174        attributes.
175
176    """
177    output = RL("| ")
178    output += RL(
179        self.BACK_ARROW_TEXT,
180        (debugger_cli_common.MenuItem(None, backward_command)
181         if self.can_go_back() else None))
182    output += RL(" ")
183    output += RL(
184        self.FORWARD_ARROW_TEXT,
185        (debugger_cli_common.MenuItem(None, forward_command)
186         if self.can_go_forward() else None))
187
188    if self._items:
189      command_attribute = (latest_command_attribute
190                           if (self._pointer == (len(self._items) - 1))
191                           else old_command_attribute)
192      output += RL(" | ")
193      if self._pointer != len(self._items) - 1:
194        output += RL("(-%d) " % (len(self._items) - 1 - self._pointer),
195                     command_attribute)
196
197      if len(output) < max_length:
198        maybe_truncated_command = self._items[self._pointer].command[
199            :(max_length - len(output))]
200        output += RL(maybe_truncated_command, command_attribute)
201
202    return debugger_cli_common.rich_text_lines_from_rich_line_list([output])
203