author | wenzelm |
Mon, 04 Dec 2017 17:37:26 +0100 | |
changeset 67127 | cf111622c9f8 |
parent 67125 | 361b3ef643a7 |
child 67128 | 4d91b6d5d49c |
permissions | -rw-r--r-- |
65258 | 1 |
/* Title: Tools/jEdit/src/syntax_style.scala |
2 |
Author: Makarius |
|
3 |
||
4 |
Support for extended syntax styles: subscript, superscript, bold, user fonts. |
|
5 |
*/ |
|
6 |
||
7 |
package isabelle.jedit |
|
8 |
||
9 |
||
10 |
import isabelle._ |
|
11 |
||
12 |
import java.awt.{Font, Color} |
|
13 |
import java.awt.font.TextAttribute |
|
14 |
import java.awt.geom.AffineTransform |
|
15 |
||
16 |
import org.gjt.sp.util.SyntaxUtilities |
|
17 |
import org.gjt.sp.jedit.syntax.{Token => JEditToken, SyntaxStyle} |
|
65259 | 18 |
import org.gjt.sp.jedit.textarea.TextArea |
65258 | 19 |
|
20 |
||
21 |
object Syntax_Style |
|
22 |
{ |
|
65259 | 23 |
/* extended syntax styles */ |
24 |
||
65258 | 25 |
private val plain_range: Int = JEditToken.ID_COUNT |
26 |
private val full_range = 6 * plain_range + 1 |
|
27 |
private def check_range(i: Int) { require(0 <= i && i < plain_range) } |
|
28 |
||
29 |
def subscript(i: Byte): Byte = { check_range(i); (i + plain_range).toByte } |
|
30 |
def superscript(i: Byte): Byte = { check_range(i); (i + 2 * plain_range).toByte } |
|
31 |
def bold(i: Byte): Byte = { check_range(i); (i + 3 * plain_range).toByte } |
|
32 |
def user_font(idx: Int, i: Byte): Byte = { check_range(i); (i + (4 + idx) * plain_range).toByte } |
|
33 |
val hidden: Byte = (6 * plain_range).toByte |
|
34 |
||
35 |
private def font_style(style: SyntaxStyle, f: Font => Font): SyntaxStyle = |
|
36 |
new SyntaxStyle(style.getForegroundColor, style.getBackgroundColor, f(style.getFont)) |
|
37 |
||
38 |
private def script_style(style: SyntaxStyle, i: Int): SyntaxStyle = |
|
39 |
{ |
|
40 |
font_style(style, font0 => |
|
41 |
{ |
|
42 |
import scala.collection.JavaConversions._ |
|
43 |
val font1 = font0.deriveFont(Map(TextAttribute.SUPERSCRIPT -> new java.lang.Integer(i))) |
|
44 |
||
45 |
def shift(y: Float): Font = |
|
46 |
GUI.transform_font(font1, AffineTransform.getTranslateInstance(0.0, y.toDouble)) |
|
47 |
||
48 |
val m0 = GUI.line_metrics(font0) |
|
49 |
val m1 = GUI.line_metrics(font1) |
|
50 |
val a = m1.getAscent - m0.getAscent |
|
51 |
val b = (m1.getDescent + m1.getLeading) - (m0.getDescent + m0.getLeading) |
|
52 |
if (a > 0.0f) shift(a) |
|
53 |
else if (b > 0.0f) shift(- b) |
|
54 |
else font1 |
|
55 |
}) |
|
56 |
} |
|
57 |
||
58 |
private def bold_style(style: SyntaxStyle): SyntaxStyle = |
|
59 |
font_style(style, font => font.deriveFont(if (font.isBold) Font.PLAIN else Font.BOLD)) |
|
60 |
||
61 |
val hidden_color: Color = new Color(255, 255, 255, 0) |
|
62 |
||
65261 | 63 |
object Extender extends SyntaxUtilities.StyleExtender |
65258 | 64 |
{ |
65 |
val max_user_fonts = 2 |
|
66 |
if (Symbol.font_names.length > max_user_fonts) |
|
67 |
error("Too many user symbol fonts (" + max_user_fonts + " permitted): " + |
|
68 |
Symbol.font_names.mkString(", ")) |
|
69 |
||
70 |
override def extendStyles(styles: Array[SyntaxStyle]): Array[SyntaxStyle] = |
|
71 |
{ |
|
72 |
val new_styles = new Array[SyntaxStyle](full_range) |
|
73 |
for (i <- 0 until plain_range) { |
|
74 |
val style = styles(i) |
|
75 |
new_styles(i) = style |
|
76 |
new_styles(subscript(i.toByte)) = script_style(style, -1) |
|
77 |
new_styles(superscript(i.toByte)) = script_style(style, 1) |
|
78 |
new_styles(bold(i.toByte)) = bold_style(style) |
|
79 |
for (idx <- 0 until max_user_fonts) |
|
80 |
new_styles(user_font(idx, i.toByte)) = style |
|
81 |
for ((family, idx) <- Symbol.font_index) |
|
82 |
new_styles(user_font(idx, i.toByte)) = font_style(style, GUI.imitate_font(_, family)) |
|
83 |
} |
|
84 |
new_styles(hidden) = |
|
85 |
new SyntaxStyle(hidden_color, null, |
|
86 |
{ val font = styles(0).getFont |
|
87 |
GUI.transform_font(new Font(font.getFamily, 0, 1), |
|
88 |
AffineTransform.getScaleInstance(1.0, font.getSize.toDouble)) }) |
|
89 |
new_styles |
|
90 |
} |
|
91 |
} |
|
92 |
||
67127
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
93 |
private def control_style(sym: String): Option[Byte => Byte] = |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
94 |
if (sym == Symbol.sub_decoded) Some(subscript(_)) |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
95 |
else if (sym == Symbol.sup_decoded) Some(superscript(_)) |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
96 |
else if (sym == Symbol.bold_decoded) Some(bold(_)) |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
97 |
else None |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
98 |
|
65258 | 99 |
def extended(text: CharSequence): Map[Text.Offset, Byte => Byte] = |
100 |
{ |
|
101 |
var result = Map[Text.Offset, Byte => Byte]() |
|
102 |
def mark(start: Text.Offset, stop: Text.Offset, style: Byte => Byte) |
|
103 |
{ |
|
104 |
for (i <- start until stop) result += (i -> style) |
|
105 |
} |
|
67127
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
106 |
|
65258 | 107 |
var offset = 0 |
108 |
var control = "" |
|
109 |
for (sym <- Symbol.iterator(text)) { |
|
67127
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
110 |
val end_offset = offset + sym.length |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
111 |
|
65258 | 112 |
if (control_style(sym).isDefined) control = sym |
113 |
else if (control != "") { |
|
66006
cec184536dfd
uniform notion of Symbol.is_controllable (see also 265d9300d523);
wenzelm
parents:
65997
diff
changeset
|
114 |
if (Symbol.is_controllable(sym) && !Symbol.fonts.isDefinedAt(sym)) { |
65258 | 115 |
mark(offset - control.length, offset, _ => hidden) |
67127
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
116 |
mark(offset, end_offset, control_style(control).get) |
65258 | 117 |
} |
118 |
control = "" |
|
119 |
} |
|
67127
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
120 |
|
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
121 |
if (Symbol.is_control_encoded(sym)) { |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
122 |
val a = offset + Symbol.control_prefix.length |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
123 |
val b = end_offset - Symbol.control_suffix.length |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
124 |
mark(offset, a, _ => hidden) |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
125 |
mark(a, b, _ => JEditToken.KEYWORD4) |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
126 |
mark(b, end_offset, _ => hidden) |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
127 |
} |
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
128 |
|
65258 | 129 |
Symbol.lookup_font(sym) match { |
67127
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
130 |
case Some(idx) => mark(offset, end_offset, user_font(idx, _)) |
65258 | 131 |
case _ => |
132 |
} |
|
67127
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
133 |
|
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
134 |
offset = end_offset |
65258 | 135 |
} |
67127
cf111622c9f8
font style for literal control symbols, notably for antiquotations;
wenzelm
parents:
67125
diff
changeset
|
136 |
|
65258 | 137 |
result |
138 |
} |
|
65259 | 139 |
|
140 |
||
141 |
/* editing support for control symbols */ |
|
142 |
||
143 |
def edit_control_style(text_area: TextArea, control: String) |
|
144 |
{ |
|
145 |
GUI_Thread.assert {} |
|
146 |
||
147 |
val buffer = text_area.getBuffer |
|
148 |
||
149 |
val control_decoded = Isabelle_Encoding.maybe_decode(buffer, control) |
|
150 |
||
151 |
def update_style(text: String): String = |
|
152 |
{ |
|
153 |
val result = new StringBuilder |
|
65997
e3dc9ea67a62
output control symbols like ML version, with optionally hidden source;
wenzelm
parents:
65265
diff
changeset
|
154 |
for (sym <- Symbol.iterator(text) if !HTML.is_control(sym)) { |
65259 | 155 |
if (Symbol.is_controllable(sym)) result ++= control_decoded |
156 |
result ++= sym |
|
157 |
} |
|
158 |
result.toString |
|
159 |
} |
|
160 |
||
161 |
text_area.getSelection.foreach(sel => { |
|
162 |
val before = JEdit_Lib.point_range(buffer, sel.getStart - 1) |
|
67014 | 163 |
JEdit_Lib.get_text(buffer, before) match { |
65997
e3dc9ea67a62
output control symbols like ML version, with optionally hidden source;
wenzelm
parents:
65265
diff
changeset
|
164 |
case Some(s) if HTML.is_control(s) => |
65259 | 165 |
text_area.extendSelection(before.start, before.stop) |
166 |
case _ => |
|
167 |
} |
|
168 |
}) |
|
169 |
||
170 |
text_area.getSelection.toList match { |
|
171 |
case Nil => |
|
172 |
text_area.setSelectedText(control_decoded) |
|
173 |
case sels => |
|
174 |
JEdit_Lib.buffer_edit(buffer) { |
|
175 |
sels.foreach(sel => |
|
176 |
text_area.setSelectedText(sel, update_style(text_area.getSelectedText(sel)))) |
|
177 |
} |
|
178 |
} |
|
179 |
} |
|
65258 | 180 |
} |