From 3ba090d4cb6e1322e5ac1f95f8b3565857bfb1d6 Mon Sep 17 00:00:00 2001 From: gazer Date: Tue, 26 Jan 2016 23:59:30 +0300 Subject: [PATCH] ascii-unicode improvements --- src/dlangui/core/cssparser.d | 40 +++++++++++---------------- src/dlangui/core/editable.d | 17 +++++------- src/dlangui/core/settings.d | 30 +++++++-------------- src/dlangui/core/types.d | 51 +++++++++++------------------------ src/dlangui/dml/parser.d | 4 +-- src/dlangui/graphics/colors.d | 13 +-------- src/dlangui/widgets/layouts.d | 2 +- src/dlangui/widgets/menu.d | 4 +-- 8 files changed, 51 insertions(+), 110 deletions(-) diff --git a/src/dlangui/core/cssparser.d b/src/dlangui/core/cssparser.d index 669837b3..42797bf6 100644 --- a/src/dlangui/core/cssparser.d +++ b/src/dlangui/core/cssparser.d @@ -5,10 +5,11 @@ import std.conv : to; import std.string; import std.array : empty; import std.algorithm : equal; -import std.ascii : isAlpha; +import std.ascii : isAlpha, isWhite; import dlangui.core.dom; import dlangui.core.css; +import dlangui.core.types : parseHexDigit; /// skip specified count of chars of string, returns next available character, or 0 if end of string reached private char skip(ref string src, int count = 1) { @@ -33,7 +34,7 @@ private char skipSpaces(ref string str) char ch = str.peek; if (!ch) return 0; - while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + while (isWhite(ch)) ch = str.skip; if (str.peek == '/' && str.peek(1) == '*') { // comment found @@ -44,7 +45,7 @@ private char skipSpaces(ref string str) str.skip(2); } ch = str.peek; - while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + while (isWhite(ch)) ch = str.skip; if (oldpos.ptr is str.ptr) break; @@ -57,7 +58,7 @@ private char skipSpaces(ref string str) private bool isIdentChar(char ch) { - return (ch >= 'A' && ch <='Z') || (ch >= 'a' && ch <='z') || (ch == '-') || (ch == '_'); + return isAlpha(ch) || (ch == '-') || (ch == '_'); } /// parse css identifier @@ -143,17 +144,6 @@ private bool nextProperty(ref string str) { } -private int hexDigit( char c ) -{ - if ( c >= '0' && c <= '9' ) - return c-'0'; - if ( c >= 'A' && c <= 'F' ) - return c - 'A' + 10; - if ( c >= 'a' && c <= 'f' ) - return c - 'a' + 10; - return -1; -} - private int parseStandardColor(string ident) { switch(ident) { case "black": return 0x000000; @@ -205,23 +195,23 @@ private bool parseColor(ref string src, ref CssValue value) // #rgb or #rrggbb colors ch = src.skip; int nDigits = 0; - for ( ; nDigits < src.length && hexDigit(src[nDigits])>=0; nDigits++ ) { + for ( ; nDigits < src.length && parseHexDigit(src[nDigits])>=0; nDigits++ ) { } if ( nDigits==3 ) { - int r = hexDigit( src[0] ); - int g = hexDigit( src[1] ); - int b = hexDigit( src[2] ); + int r = parseHexDigit( src[0] ); + int g = parseHexDigit( src[1] ); + int b = parseHexDigit( src[2] ); value.type = CssValueType.color; value.value = (((r + r*16) * 256) | (g + g*16)) * 256 | (b + b*16); src.skip(3); return true; } else if ( nDigits==6 ) { - int r = hexDigit( src[0] ) * 16; - r += hexDigit( src[1] ); - int g = hexDigit( src[2] ) * 16; - g += hexDigit( src[3] ); - int b = hexDigit( src[4] ) * 16; - b += hexDigit( src[5] ); + int r = parseHexDigit( src[0] ) * 16; + r += parseHexDigit( src[1] ); + int g = parseHexDigit( src[2] ) * 16; + g += parseHexDigit( src[3] ); + int b = parseHexDigit( src[4] ) * 16; + b += parseHexDigit( src[5] ); value.type = CssValueType.color; value.value = ((r * 256) | g) * 256 | b; src.skip(6); diff --git a/src/dlangui/core/editable.d b/src/dlangui/core/editable.d index f9df5303..775a25ef 100644 --- a/src/dlangui/core/editable.d +++ b/src/dlangui/core/editable.d @@ -626,9 +626,7 @@ class EditableContent { performOperation(op, this); } - static bool isAlphaForWordSelection(dchar ch) { - return ch == '_' || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); - } + static alias isAlphaForWordSelection = isAlNum; /// get word bounds by position TextRange wordBounds(TextPosition pos) { @@ -1133,21 +1131,18 @@ class EditableContent { } } - static bool isDigit(dchar ch) pure nothrow { - return ch >= '0' && ch <= '9'; - } + + static alias isDigit = std.uni.isNumber; static bool isAlpha(dchar ch) pure nothrow { - return isLowerAlpha(ch) || isUpperAlpha(ch); + return std.uni.isAlpha(ch) || ch == '_'; } static bool isAlNum(dchar ch) pure nothrow { return isDigit(ch) || isAlpha(ch); } static bool isLowerAlpha(dchar ch) pure nothrow { - return (ch >= 'a' && ch <= 'z') || (ch == '_'); - } - static bool isUpperAlpha(dchar ch) pure nothrow { - return (ch >= 'A' && ch <= 'Z'); + return std.uni.isLower(ch) || ch == '_'; } + static alias isUpperAlpha = std.uni.isUpper; static bool isPunct(dchar ch) pure nothrow { switch(ch) { case '.': diff --git a/src/dlangui/core/settings.d b/src/dlangui/core/settings.d index a60c2c4b..fd5dc262 100644 --- a/src/dlangui/core/settings.d +++ b/src/dlangui/core/settings.d @@ -27,6 +27,7 @@ Authors: Vadim Lopatin, coolreader.org@gmail.com module dlangui.core.settings; import dlangui.core.logger; +import dlangui.core.types : parseHexDigit; import std.range; import std.algorithm : equal; import std.conv : to; @@ -1623,42 +1624,28 @@ final class Setting { context = "near `" ~ json[contextStart .. contextEnd] ~ "` "; throw new Exception("JSON parsing error in (" ~ to!string(line) ~ ":" ~ to!string(col) ~ ") " ~ context ~ ": " ~ msg); } - static bool isSpace(char ch) { - return ch== ' ' || ch == '\t' || ch == '\r' || ch == '\n'; - } static bool isAlpha(char ch) { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_'; + return std.ascii.isAlpha(ch) || ch == '_'; } static bool isAlNum(char ch) { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_'; - } - static bool isDigit(char ch) { - return (ch >= '0' && ch <= '9'); + return std.ascii.isAlphaNum(ch) || ch == '_'; } @property char skipSpaces() { for(;pos < json.length;pos++) { char ch = json[pos]; - if (!isSpace(ch)) + if (!std.ascii.isWhite(ch)) break; } return peek; } - static int parseHexDigit(char ch) { - if (ch >= '0' && ch <='9') - return ch - '0'; - if (ch >= 'a' && ch <='f') - return ch - 'a' + 10; - if (ch >= 'A' && ch <='F') - return ch - 'A' + 10; - return -1; - } + string parseUnicodeChar() { if (pos >= json.length - 3) error("unexpected end of file while parsing unicode character entity inside string"); dchar ch = 0; foreach(i; 0 .. 4) { - int d = parseHexDigit(nextChar); - if (d < 0) + uint d = parseHexDigit(nextChar); + if (d == uint.max) error("error while parsing unicode character entity inside string"); ch = (ch << 4) | d; } @@ -1756,6 +1743,7 @@ final class Setting { // parse long, ulong or double void parseNumber(Setting res) { + import std.ascii : isDigit; char ch = peek; int sign = 1; if (ch == '-') { @@ -1886,7 +1874,7 @@ final class Setting { this = true; } else if (parser.parseKeyword("false")) { this = false; - } else if (ch == '-' || JsonParser.isDigit(ch)) { + } else if (ch == '-' || std.ascii.isDigit(ch)) { parser.parseNumber(this); } else { parser.error("cannot parse JSON value"); diff --git a/src/dlangui/core/types.d b/src/dlangui/core/types.d index d50e0757..e59dd503 100644 --- a/src/dlangui/core/types.d +++ b/src/dlangui/core/types.d @@ -45,19 +45,13 @@ public import dlangui.core.config; import std.algorithm; -/** 2D point */ +/// 2D point struct Point { - /// x coordinate int x; - /// y coordinate int y; - this(int x0, int y0) { - x = x0; - y = y0; - } } -/** 2D rectangle */ +/// 2D rectangle struct Rect { /// x coordinate of top left corner int left; @@ -427,26 +421,6 @@ struct Ref(T) { // if (T is RefCountedObject) //================================================================================ // some utility functions -/* -string fromStringz(const(char[]) s) { - if (s is null) - return null; - int i = 0; - while(s[i]) - i++; - return cast(string)(s[0..i].dup); -} - -string fromStringz(const(char*) s) { - if (s is null) - return null; - int i = 0; - while(s[i]) - i++; - return cast(string)(s[0..i].dup); -} -*/ - /** conversion from wchar z-string */ wstring fromWStringz(const(wchar[]) s) { if (s is null) @@ -497,15 +471,20 @@ enum State : uint { Parent = 0x10000, // use parent's state } -/** +/** Deprecated: use std.uni.toUpper instead. Uppercase unicode character. - - TODO: support non-ascii. */ -dchar dcharToUpper(dchar ch) { - // TODO: support non-ascii letters - if (ch >= 'a' && ch <= 'z') - return ch - 'a' + 'A'; - return ch; +deprecated dchar dcharToUpper(dchar ch) { + return std.uni.toUpper(ch); } +/// decodes hex digit (0..9, a..f, A..F), returns uint.max if invalid +uint parseHexDigit(T)(T ch) pure nothrow { + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + return uint.max; +} diff --git a/src/dlangui/dml/parser.d b/src/dlangui/dml/parser.d index f01b7b4c..ec8dd3f3 100644 --- a/src/dlangui/dml/parser.d +++ b/src/dlangui/dml/parser.d @@ -347,13 +347,13 @@ class Tokenizer { foreach(i; 0 .. prefixLen) ch = skipChar(); - uint n = decodeHexDigit(ch); + uint n = parseHexDigit(ch); if (n == uint.max) return parseError(); for(;;) { ch = skipChar(); - uint digit = decodeHexDigit(ch); + uint digit = parseHexDigit(ch); if (digit == uint.max) break; n = (n << 4) + digit; diff --git a/src/dlangui/graphics/colors.d b/src/dlangui/graphics/colors.d index f154b2b1..fb2538c2 100644 --- a/src/dlangui/graphics/colors.d +++ b/src/dlangui/graphics/colors.d @@ -163,17 +163,6 @@ bool isFullyTransparentColor(uint color) pure nothrow { return (color >> 24) == 0xFF; } -/// decodes hex digit (0..9, a..f, A..F), returns uint.max if invalid -uint decodeHexDigit(T)(T ch) pure nothrow { - if (ch >= '0' && ch <= '9') - return ch - '0'; - else if (ch >= 'a' && ch <= 'f') - return ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') - return ch - 'A' + 10; - return uint.max; -} - /// decode color string supported formats: #RGB #ARGB #RRGGBB #AARRGGBB uint decodeHexColor(string s, uint defValue = 0) pure { s = strip(s); @@ -205,7 +194,7 @@ uint decodeHexColor(string s, uint defValue = 0) pure { return defValue; uint value = 0; foreach(i; 1 .. s.length) { - uint digit = decodeHexDigit(s[i]); + uint digit = parseHexDigit(s[i]); if (digit == uint.max) return defValue; value = (value << 4) | digit; diff --git a/src/dlangui/widgets/layouts.d b/src/dlangui/widgets/layouts.d index 692553c5..8014c460 100644 --- a/src/dlangui/widgets/layouts.d +++ b/src/dlangui/widgets/layouts.d @@ -7,7 +7,7 @@ Layouts are similar to the same in Android. LinearLayout - either VerticalLayout or HorizontalLayout. VerticalLayout - just LinearLayout with orientation=Orientation.Vertical -HorizontalLayout - just LinearLayout with orientation=Orientation.Vertical +HorizontalLayout - just LinearLayout with orientation=Orientation.Horizontal FrameLayout - children occupy the same place, usually one one is visible at a time TableLayout - children aligned into rows and columns ResizerWidget - widget to resize sibling widgets diff --git a/src/dlangui/widgets/menu.d b/src/dlangui/widgets/menu.d index c189a697..5ea633de 100644 --- a/src/dlangui/widgets/menu.d +++ b/src/dlangui/widgets/menu.d @@ -155,14 +155,14 @@ class MenuItem { break; } } - return dcharToUpper(ch); + return std.uni.toUpper(ch); } /// find subitem by hotkey character, returns subitem index, -1 if not found int findSubitemByHotkey(dchar ch) { if (!ch) return -1; - ch = dcharToUpper(ch); + ch = std.uni.toUpper(ch); for (int i = 0; i < _subitems.length; i++) { if (_subitems[i].getHotkey() == ch) return i;