Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/txt/DecodeTXTClipboardMacro.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/txt/DecodeTXTClipboardMacro.groovy	(revision 0)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/macro/txt/DecodeTXTClipboardMacro.groovy	(revision 3527)
@@ -0,0 +1,179 @@
+// Copyright © 2022 ENS de Lyon - https://www.textometrie.org
+// @author sheiden
+
+package org.txm.macro.txt
+// STANDARD DECLARATIONS
+
+import java.lang.Character
+import java.awt.Font
+import java.awt.event.KeyEvent
+
+def TypeCode2TypeName(tc) {
+
+	types = [ Character.COMBINING_SPACING_MARK, Character.CONNECTOR_PUNCTUATION, Character.CONTROL,
+                Character.CURRENCY_SYMBOL, Character.DASH_PUNCTUATION, Character.DECIMAL_DIGIT_NUMBER,
+                Character.ENCLOSING_MARK, Character.END_PUNCTUATION, Character.FORMAT, Character.LETTER_NUMBER,
+                Character.LINE_SEPARATOR, Character.LOWERCASE_LETTER, Character.MATH_SYMBOL,
+                Character.MODIFIER_SYMBOL, Character.NON_SPACING_MARK, Character.OTHER_LETTER,
+                Character.OTHER_NUMBER, Character.OTHER_PUNCTUATION, Character.OTHER_SYMBOL,
+                Character.PARAGRAPH_SEPARATOR, Character.PRIVATE_USE, Character.SPACE_SEPARATOR,
+                Character.START_PUNCTUATION, Character.SURROGATE, Character.TITLECASE_LETTER, Character.UNASSIGNED,
+                Character.UPPERCASE_LETTER ]
+                                                 
+	typeNames = [ "Combining spacing mark", "Connector punctuation", "Control", "Currency symbol",
+                "Dash punctuation", "Decimal digit number", "Enclosing mark", "End punctuation", "Format",
+                "Letter number", "Line separator", "Lowercase letter", "Math symbol", "Modifier symbol",
+                "Non spacing mark", "Other letter", "Other number", "Other punctuation", "Other symbol",
+                "Paragraph separator", "Private use", "Space separator", "Start punctuation", "Surrogate",
+                "Titlecase letter", "Unassigned", "Uppercase letter" ]
+                
+	for (int i = 0; i < types.size(); i++) {
+        	if (tc == types[i]) {
+            	return(typeNames[i])
+            	}
+	}
+	return "Unknown"
+}
+
+def DirectionalityCode2DirectionalityName(dc) {
+
+	directionalities = [
+		Character.DIRECTIONALITY_ARABIC_NUMBER,
+		Character.DIRECTIONALITY_BOUNDARY_NEUTRAL,
+		Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR,
+		Character.DIRECTIONALITY_EUROPEAN_NUMBER,
+		Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR,
+		Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR,
+		Character.DIRECTIONALITY_LEFT_TO_RIGHT,
+		Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING,
+		Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE,
+		Character.DIRECTIONALITY_NONSPACING_MARK,
+		Character.DIRECTIONALITY_OTHER_NEUTRALS,
+		Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR,
+		Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT,
+		Character.DIRECTIONALITY_RIGHT_TO_LEFT,
+		Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC,
+		Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING,
+		Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE,
+		Character.DIRECTIONALITY_SEGMENT_SEPARATOR,
+		Character.DIRECTIONALITY_UNDEFINED,
+		Character.DIRECTIONALITY_WHITESPACE
+	]
+
+	directionalitiesNames = [
+		"Arabic Number",
+		"Boundary Neutral",
+		"Common Number Separator",
+		"European Number",
+		"European Number Separator",
+		"European Number Terminator",
+		"Left To Right",
+		"Left To Right Embedding",
+		"Left To Right Override",
+		"Nonspacing Mark",
+		"Other Neutrals",
+		"Paragraph Separator",
+		"Pop Directional Format",
+		"Right To Left",
+		"Right To Left Arabic",
+		"Right To Left Embedding",
+		"Right To Left Override",
+		"Segment Separator",
+		"Undefined",
+		"Whitespace"
+	]
+	
+	for (int i = 0; i < directionalities.size(); i++) {
+        	if (dc == directionalities[i]) {
+            	return(directionalitiesNames[i])
+            	}
+	}
+	return "Unknown"
+}
+
+def isPrintableChar(c) {
+    Character.UnicodeBlock block = Character.UnicodeBlock.of( c )
+    return (!Character.isISOControl(c)) &&
+            c != KeyEvent.CHAR_UNDEFINED &&
+            block != null &&
+            block != Character.UnicodeBlock.SPECIALS;
+}
+
+monitor.syncExec(new Runnable() {
+	public void run() {
+		try {
+			s = org.txm.rcp.utils.IOClipboard.read()
+			if (s == null || s.length() == 0) {
+				println "No text in clipboard. Aborting."
+				return
+			}
+        
+			l = s.length()
+			maxcodeL = 0
+			maxnameL = 0
+			maxtypeL = 0
+			maxscriptL = 0
+			maxblockL = 0
+			maxdirectL = 0
+			for (int i = 0; i < l; i++) {
+				c = s.substring(i, i+1)
+				
+				cp = s.codePointAt(i)
+				name = Character.getName(cp)
+				type = TypeCode2TypeName(Character.getType(cp))
+				script = Character.UnicodeScript.of(cp).name()
+				block = Character.UnicodeBlock.of(cp)
+				direct = DirectionalityCode2DirectionalityName(Character.getDirectionality(cp))
+				
+				cpsl = cp.toString().length()
+				if (cpsl > maxcodeL) maxcodeL = cpsl
+				namesl = name.toString().length()
+				if (namesl > maxnameL) maxnameL = namesl
+				typesl = type.toString().length()
+				if (typesl > maxtypeL) maxtypeL = typesl
+				scriptsl = script.toString().length()
+				if (scriptsl > maxscriptL) maxscriptL = scriptsl
+				blocksl = block.toString().length()
+				if (blocksl > maxblockL) maxblockL = blocksl
+				directsl = direct.toString().length()
+				if (directsl > maxdirectL) maxdirectL = directsl
+			}
+			
+			if (maxcodeL < 4) maxcodeL = 4
+			if (maxnameL < 4) maxnameL = 4
+			if (maxtypeL < 4) maxtypeL = 4
+			if (maxscriptL < 6) maxscriptL = 6
+			if (maxblockL < 5) maxblockL = 5
+			if (maxdirectL < 14) maxdirectL = 14
+
+			println sprintf("%-15s %${maxcodeL}s %-${maxnameL}s %-${maxtypeL}s %-${maxscriptL}s %-${maxblockL}s %-${maxdirectL}s", "Char", "Code", "Name", "Type", "Script", "Block", "Directionality")
+			for (int i = 0; i < l; i++) {
+				c = s.substring(i, i+1)
+				cp = s.codePointAt(i)
+				name = Character.getName(cp)
+				type = TypeCode2TypeName(Character.getType(cp))
+				script = Character.UnicodeScript.of(cp).name()
+				block = Character.UnicodeBlock.of(cp)
+				direct = DirectionalityCode2DirectionalityName(Character.getDirectionality(cp))
+				if (isPrintableChar(c.charAt(0))) {
+					println sprintf("%-15s %${maxcodeL}s %-${maxnameL}s %-${maxtypeL}s %-${maxscriptL}s %-${maxblockL}s %-${maxdirectL}s", c, cp, name, type, script, block, direct)
+				} else {
+					println sprintf("<not printable> %${maxcodeL}s %-${maxnameL}s %-${maxtypeL}s %-${maxscriptL}s %-${maxblockL}s %-${maxdirectL}s", cp, name, type, script, block, direct)
+				}				
+			}
+/*
+			for (char c : s) {
+				charValue = c.charValue()
+				charName = java.lang.Character.getName(c)
+				numericValue = java.lang.Character.getNumericValue(c)
+				charType = java.lang.Character.getType(c)
+
+			}
+*/
+
+		} catch (Exception e) {
+			e.printStackTrace()
+		}
+	}
+})
+
