summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/ext/utfwidth.py121
-rw-r--r--ranger/gui/bar.py15
-rw-r--r--ranger/gui/curses_shortcuts.py30
-rw-r--r--ranger/gui/widgets/browsercolumn.py8
-rw-r--r--test/tc_utfwidth.py7
5 files changed, 77 insertions, 104 deletions
diff --git a/ranger/ext/utfwidth.py b/ranger/ext/utfwidth.py
index 5c850607..a506c676 100644
--- a/ranger/ext/utfwidth.py
+++ b/ranger/ext/utfwidth.py
@@ -18,80 +18,49 @@
 # ----
 # This file contains portions of code from cmus (uchar.c).
 
-"""
-This module provides functions that operate with the width of characters
-and strings rather than characters or bytes.
-"""
-
-import sys
-
 NARROW = 1
 WIDE = 2
 
-if sys.version > '3':
-	def uwid(string, count=-1):
-		"""Return the width of a string"""
-		width = 0
-		for c in string:
-			width += utf_char_width(c)
-			count -= 1
-			if not count:
-				break
-		return width
-
-	def uchars(string):
-		"""Return a list with one string for each character"""
-		return list(string)
+def uwid(string):
+	"""Return the width of a string"""
+	end = len(string)
+	i = 0
+	width = 0
+	while i < end:
+		bytelen = utf_byte_length(string[i:])
+		width += utf_char_width(string[i:i+bytelen])
+		i += bytelen
+	return width
 
-	utf_ord = ord
-else:
-	def uwid(string, count=-1):
-		"""Return the width of a string"""
-		end = len(string)
-		i = 0
-		width = 0
-		while i < end and count:
-			bytelen = _utf_byte_length(string[i:])
-			width += utf_char_width(string[i:i+bytelen])
-			i += bytelen
-			count -= 1
-		return width
+def uchars(string):
+	"""Return a list with one string for each character"""
+	end = len(string)
+	i = 0
+	result = []
+	while i < end:
+		bytelen = utf_byte_length(string[i:])
+		result.append(string[i:i+bytelen])
+		i += bytelen
+	return result
 
-	def uchars(string):
-		"""Return a list with one string for each character"""
-		end = len(string)
-		i = 0
-		result = []
-		while i < end:
-			bytelen = _utf_byte_length(string[i:])
-			result.append(string[i:i+bytelen])
-			i += bytelen
-		return result
-
-	def _utf_byte_length(string):
-		"""Return the byte length of one utf character"""
-		firstord = ord(string[0])
-		if firstord < 0b01111111:
-			return 1
-		if firstord < 0b10111111:
-			return 1  # invalid
-		if firstord < 0b11011111:
-			return 2
-		if firstord < 0b11101111:
-			return 3
-		if firstord < 0b11110100:
-			return 4
+def utf_byte_length(string):
+	"""Return the byte length of one utf character"""
+	firstord = ord(string[0])
+	if firstord < 0b01111111:
+		return 1
+	if firstord < 0b10111111:
 		return 1  # invalid
-
-	def utf_ord(char):
-		value = 0
-		for byte in char:
-			value = (value << 6) | (ord(byte) & 0b00111111)
-		return value
+	if firstord < 0b11011111:
+		return 2
+	if firstord < 0b11101111:
+		return 3
+	if firstord < 0b11110100:
+		return 4
+	return 1  # invalid
 
 def utf_char_width(string):
 	"""Return the width of a single character"""
-	u = utf_ord(string)
+	u = _utf_char_to_int(string)
 	if u < 0x1100:
 		return NARROW
 	# Hangul Jamo init. constonants
@@ -132,19 +101,9 @@ def utf_char_width(string):
 		return WIDE
 	return NARROW  # invalid (?)
 
-def uslice(string, start=0, end=1000000000):
-	"""
-	Returns a sliced string.
-
-	Works like string[start:end] except that one step represents
-	one narrow character in a monospaced character grid.
-	"""
-	chars = []
-	for c in uchars(string):
-		c_wid = utf_char_width(c)
-		if c_wid == NARROW:
-			chars.append(c)
-		elif c_wid == WIDE:
-			chars.append("")
-			chars.append(c)
-	return "".join(chars[start:end])
+def _utf_char_to_int(string):
+	# Squash the last 6 bits of each byte together to an integer
+	u = 0
+	for c in string:
+		u = (u << 6) | (ord(c) & 0b00111111)
+	return u
diff --git a/ranger/gui/bar.py b/ranger/gui/bar.py
index 42e1f1c4..41cc8133 100644
--- a/ranger/gui/bar.py
+++ b/ranger/gui/bar.py
@@ -13,7 +13,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from ranger.ext.utfwidth import uwid, uslice, utf_char_width
+from ranger.ext.utfwidth import uwid
 
 class Bar(object):
 	left = None
@@ -75,11 +75,10 @@ class Bar(object):
 		# Shrink items to a minimum size of 1 until there is enough room.
 		for item in self.left:
 			if not item.fixed:
-				itemlen = uwid(item.string)
-				minimal_width = uwid(item.string, count=1)
-				if oversize > itemlen - minimal_width:
-					item.cut_off_to(minimal_width)
-					oversize -= (itemlen - minimal_width)
+				itemlen = len(item)
+				if oversize > itemlen - 1:
+					item.cut_off_to(1)
+					oversize -= (itemlen - 1)
 				else:
 					item.cut_off(oversize)
 					break
@@ -133,10 +132,10 @@ class ColoredString(object):
 
 	def cut_off(self, n):
 		if n >= 1:
-			self.string = uslice(self.string, 0, -n)
+			self.string = self.string[:-n]
 
 	def cut_off_to(self, n):
-		self.string = uslice(self.string, 0, n)
+		self.string = self.string[:n]
 
 	def __len__(self):
 		return uwid(self.string)
diff --git a/ranger/gui/curses_shortcuts.py b/ranger/gui/curses_shortcuts.py
index e5683b66..3df45700 100644
--- a/ranger/gui/curses_shortcuts.py
+++ b/ranger/gui/curses_shortcuts.py
@@ -44,26 +44,38 @@ class CursesShortcuts(SettingsAware):
 	addstr(*args) -- failsafe version of self.win.addstr(*args)
 	"""
 
-	def _addxyz_wrapper(self, function, args):
+	def addstr(self, *args):
 		try:
-			function(*args)
+			self.win.addstr(*args)
 		except (_curses.error, TypeError):
 			pass
 		except UnicodeEncodeError:
 			try:
-				function(*(obj.encode('utf8') if hasattr(obj, 'encode') \
-						else obj for obj in args))
+				self.win.addstr(*(ascii_only(obj) for obj in args))
 			except (_curses.error, TypeError):
 				pass
 
-	def addstr(self, *args):
-		self._addxyz_wrapper(self.win.addstr, args)
-
 	def addnstr(self, *args):
-		self._addxyz_wrapper(self.win.addnstr, args)
+		try:
+			self.win.addnstr(*args)
+		except (_curses.error, TypeError):
+			pass
+		except UnicodeEncodeError:
+			try:
+				self.win.addnstr(*(ascii_only(obj) for obj in args))
+			except (_curses.error, TypeError):
+				pass
 
 	def addch(self, *args):
-		self._addxyz_wrapper(self.win.addch, args)
+		try:
+			self.win.addch(*args)
+		except (_curses.error, TypeError):
+			pass
+		except UnicodeEncodeError:
+			try:
+				self.win.addch(*(ascii_only(obj) for obj in args))
+			except (_curses.error, TypeError):
+				pass
 
 	def color(self, *keys):
 		"""Change the colors from now on."""
diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py
index 6021d622..d617e64e 100644
--- a/ranger/gui/widgets/browsercolumn.py
+++ b/ranger/gui/widgets/browsercolumn.py
@@ -20,7 +20,6 @@ from time import time
 from . import Widget
 from .pager import Pager
 from ranger.fsobject import BAD_INFO
-from ranger.ext.utfwidth import uslice
 
 class BrowserColumn(Pager):
 	main_column = False
@@ -249,13 +248,14 @@ class BrowserColumn(Pager):
 				this_color.append('link')
 				this_color.append(drawn.exists and 'good' or 'bad')
 
+			string = drawn.basename
 			if self.main_column:
 				if tagged:
-					self.addstr(line, 0, uslice(text, 0, self.wid - 2))
+					self.addnstr(line, 0, text, self.wid - 2)
 				elif self.wid > 1:
-					self.addstr(line, 1, uslice(text, 0, self.wid - 2))
+					self.addnstr(line, 1, text, self.wid - 2)
 			else:
-				self.addstr(line, 0, uslice(text, 0, self.wid))
+				self.addnstr(line, 0, text, self.wid)
 
 			if self.display_infostring and drawn.infostring \
 					and self.settings.display_size_in_main_column:
diff --git a/test/tc_utfwidth.py b/test/tc_utfwidth.py
index fba9f783..0288c17b 100644
--- a/test/tc_utfwidth.py
+++ b/test/tc_utfwidth.py
@@ -29,6 +29,11 @@ a_katakana = "ア"  # width = 2, bytes = 3
 # need one with width = 1 & bytes = 3
 
 class Test(TestCase):
+	def test_utf_byte_length(self):
+		self.assertEqual(1, utf_byte_length(a_ascii))
+		self.assertEqual(2, utf_byte_length(a_umlaut))
+		self.assertEqual(3, utf_byte_length(a_katakana))
+
 	def test_uwid(self):
 		self.assertEqual(1, uwid(a_ascii))
 		self.assertEqual(1, uwid(a_umlaut))
@@ -37,7 +42,5 @@ class Test(TestCase):
 		self.assertEqual(4, uwid("asdf"))
 		self.assertEqual(5, uwid("löööl"))
 		self.assertEqual(6, uwid("バババ"))
-		self.assertEqual(1, uwid("äsdf", count=1))
-		self.assertEqual(2, uwid("バババ", count=1))
 
 if __name__ == '__main__': main()