1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
|
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="macro-basics">
<title>Macro Basics</title>
<!-- jEdit 4.0 Macro Guide, (C) 2001, 2002 John Gellene -->
<!-- jEdit buffer-local properties: -->
<!-- :indentSize=1:noTabs=yes:maxLineLen=72:tabSize=2: -->
<!-- :xml.root=users-guide.xml: -->
<!-- This file cover the introductory section of the macro guide -->
<!-- $Id: macro-basics.xml 16181 2009-09-08 19:26:57Z ezust $ -->
<section id="beanshell-intro">
<title>Introducing BeanShell</title>
<para>Here is how BeanShell's author, Pat Niemeyer, describes his
creation:</para>
<blockquote>
<para><quote>BeanShell is a small, free, embeddable, Java source
interpreter with object scripting language features, written in
Java. BeanShell executes standard Java statements and expressions,
in addition to obvious scripting commands and syntax. BeanShell
supports scripted objects as simple method closures like those in
Perl and JavaScript.</quote></para>
</blockquote>
<para>You do not have to know anything about Java to begin writing your
own jEdit macros. But if you know how to program in Java, you already
know how to write BeanShell scripts. The major strength of using
BeanShell with a program written in Java is that it allows the user to
customize the program's behavior using the same interfaces designed and
used by the program itself. BeanShell can turn a well-designed
application into a powerful, extensible toolkit.</para>
<para>This guide focuses on using BeanShell in macros. If you are
interested in learning more about BeanShell generally, consult the
<ulink url="http://www.beanshell.org">BeanShell web site</ulink>.
Information on how to run and organize macros, whether included with the
jEdit installation or written by you, can be found in <xref
linkend="using-macros" />.</para>
</section>
<section id="single-macros">
<title>Single Execution Macros</title>
<para>As noted in <xref linkend="organizing-macros" />, you can save a
BeanShell script of any length as a text file with the
<filename>.bsh</filename> extension and run it from the
<guimenu>Macros</guimenu> menu. There are three other ways jEdit lets
you use BeanShell quickly, without saving a script to storage, on a
<quote>one time only</quote> basis. You will find them in the
<guimenu>Utilities</guimenu> menu.</para>
<para><guimenu>Utilities</guimenu>><guisubmenu>BeanShell</guisubmenu>><guimenuitem>Evaluate
BeanShell Expression</guimenuitem> displays a text input dialog that
asks you to type a single line of BeanShell commands. You can type more
than one BeanShell statement so long as each of them ends with a
semicolon. If BeanShell successfully interprets your input, a message
box will appear with the return value of the last statement.</para>
<para><guimenu>Utilities</guimenu>><guisubmenu>BeanShell</guisubmenu>><guimenuitem>Evaluate
For Selected Lines</guimenuitem> displays a text input dialog that asks
you to type a single line of BeanShell commands. The commands are
evaluated for each line of the selection. In addition to the standard
set of variables described in <xref linkend="predefined-variables" />,
this command defines the following:</para>
<itemizedlist>
<listitem>
<para><varname>line</varname> - the line number, from the start
of the buffer. The first line is numbered 0.</para>
</listitem>
<listitem>
<para><varname>index</varname> - the line number, from the start
of the selection. The first line is numbered 0.</para>
</listitem>
<listitem>
<para><varname>text</varname> - the text of the line.</para>
</listitem>
</itemizedlist>
<informalexample>
<para>Try typing an expression like <userinput>(line + 1) + ": " +
text</userinput> in the <guimenuitem>Evaluate For Selected
Lines</guimenuitem> dialog box. This will add a line number to each
selected line beginning with the number
<userinput>1</userinput>.</para>
</informalexample>
<para>The BeanShell expression you enter will be evaluated and
substituted in place of the entire text of a selected line. If you want
to leave the line's current text as an element of the modified line, you
must include the defined variable <userinput>text</userinput> as part of
the BeanShell expression that you enter.</para>
<para><guimenu>Utilities</guimenu>><guisubmenu>BeanShell</guisubmenu>><guimenuitem>Evaluate
Selection</guimenuitem> evaluates the selected text as a BeanShell
script and replaces it with the return value of the statement.</para>
<para>Using <guimenuitem>Evaluate Selection</guimenuitem> is an easy way
to do arithmetic calculations inline while editing. BeanShell uses
numbers and arithmetic operations in an ordinary, intuitive way.</para>
<informalexample>
<para>Try typing an expression like
<userinput>(3745*856)+74</userinput> in the buffer, select it, and
choose
<guimenu>Utilities</guimenu>><guisubmenu>BeanShell</guisubmenu>><guimenuitem>Evaluate
Selection</guimenuitem>. The selected text will be replaced by the
answer, <userinput>3205794</userinput>. <!-- Irrelevant? --> <!-- Since this is a text file
and not a spreadsheet, the original values that BeanShell evaluated are
not retained or saved as part of the buffer's contents. --></para>
</informalexample>
<sidebar>
<title>Console plugin</title>
<para>You can also do the same thing using the BeanShell interpreter
option of the <application>Console</application> plugin.</para>
</sidebar>
</section>
<section id="first-example">
<title>The Mandatory First Example</title>
<informalexample>
<!-- <title>A first one-line macro</title> -->
<programlisting>Macros.message(view, "Hello world!");</programlisting>
</informalexample>
<para>Running this one line script causes jEdit to display a message box
(more precisely, a <classname>JOptionPane</classname> object) with the
traditional beginner's message and an <guilabel>OK</guilabel> button.
Let's see what is happening here.</para>
<para>This statement calls a static method (or function) named
<function>message</function> in jEdit's <ulink
url="../api/org/gjt/sp/jedit/Macros.html">Macros</ulink> class. If you
don't know anything about classes or static methods or Java (or C++,
which employs the same concept), you will need to gain some
understanding of a few terms. Obviously this is not the place for
academic precision, but if you are entirely new to object-oriented
programming, here are a few skeleton ideas to help you with
BeanShell.</para>
<itemizedlist>
<listitem>
<para>An <glossterm>object</glossterm> is a collection of data
that can be initialized, accessed and manipulated in certain
defined ways.</para>
</listitem>
<listitem>
<para>A <glossterm>class</glossterm> is a specification of what
data an object contains and what methods can be used to work
with the data. A Java application consists of one or more
classes (in the case of jEdit ,over 600 classes) written by the
programmer that defines the application's behavior. A BeanShell
macro uses these classes, along with built-in classes that are
supplied with the Java platform, to define its own
behavior.</para>
</listitem>
<listitem>
<para>A <glossterm>subclass</glossterm> (or child class) is a
class which uses (or <quote>inherits</quote>) the data and
methods of its parent class along with additions or
modifications that alter the subclass's behavior. Classes are
typically organized in hierarchies of parent and child classes
to organize program code, to define common behavior in shared
parent class code, and to specify the types of similar behavior
that child classes will perform in their own specific
ways.</para>
</listitem>
<listitem>
<para>A <glossterm>method</glossterm> (or function) is a
procedure that works with data in a particular object, other
data (including other objects) supplied as
<glossterm>parameters</glossterm>, or both. Methods typically
are applied to a particular object which is an
<glossterm>instance</glossterm> of the class to which the method
belongs.</para>
</listitem>
<listitem>
<para>A <glossterm>static method</glossterm> differs from other
methods in that it does not deal with the data in a particular
object but is included within a class for the sake of
convenience.</para>
</listitem>
</itemizedlist>
<para>Java has a rich set of classes defined as part of the Java
platform. Like all Java applications, jEdit is organized as a set of
classes that are themselves derived from the Java platform's classes. We
will refer to <firstterm>Java classes</firstterm> and <firstterm>jEdit
classes</firstterm> to make this distinction. Some of jEdit's classes
(such as those dealing with regular expressions and XML) are derived
from or make use of classes in other open-source Java packages. Except
for BeanShell itself, we won't be discussing them in this guide.</para>
<para>In our one line script, the static method
<function>Macros.message()</function> has two parameters because that is
the way the method is defined in the <ulink
url="../api/org/gjt/sp/jedit/Macros.html">Macros</ulink> class. You must
specify both parameters when you call the function. The first parameter,
<parameter>view</parameter>, is a variable naming the current, active
<ulink url="../api/org/gjt/sp/jedit/View.html">View</ulink> object.
Information about pre-defined variables can be found in <xref
linkend="predefined-variables" />.</para>
<para>The second parameter, which appears to be quoted text, is a
<glossterm>string literal</glossterm> - a sequence of characters of
fixed length and content. Behind the scenes, BeanShell and Java take
this string literal and use it to create a <classname>String</classname>
object. Normally, if you want to create an object in Java or BeanShell,
you must construct the object using the <function>new</function> keyword
and a <firstterm>constructor</firstterm> method that is part of the
object's class. We'll show an example of that later. However, both Java
and BeanShell let you use a string literal anytime a method's parameter
calls for a <classname>String</classname>.</para>
<para>If you are a Java programmer, you might wonder about a few things
missing from this one line program. There is no class definition, for
example. You can think of a BeanShell script as an implicit definition
of a <function>main()</function> method in an anonymous class. That is
in fact how BeanShell is implemented; the class is derived from a
BeanShell class called <ulink url="../api/bsh/XThis.html">XThis</ulink>.
If you don't find that helpful, just think of a script as one or more
blocks of procedural statements conforming to Java syntax rules. You
will also get along fine (for the most part) with C or C++ syntax if you
leave out anything to do with pointers or memory management - Java and
BeanShell do not have pointers and deal with memory management
automatically.</para>
<para>Another missing item from a Java perspective is a
<function>package</function> statement. In Java, such a statement is
used to bundle together a number of files so that their classes become
visible to one another. Packages are not part of BeanShell, and you
don't need to know anything about them to write BeanShell macros.</para>
<para>Finally, there are no <function>import</function> statements in
this script. In Java, an <function>import</function> statement makes
public classes from other packages visible within the file in which the
statement occurs without having to specify a fully qualified class name.
Without an import statement or a fully qualified name, Java cannot
identify most classes using a single name as an identifier.</para>
<para>jEdit automatically imports a number of commonly-used packages
into the namespace of every BeanShell script. Because of this, the
script output of a recorded macro does not contain
<function>import</function> statements. For the same reason, most
BeanShell scripts you write will not require <function>import</function>
statements.</para>
<para>Java requires <literal>import</literal> statement to be located at
the beginning of a source file. BeanShell allows you to place
<literal>import</literal> statements anywhere in a script, including
inside a block of statements. The <literal>import</literal> statement
will cover all names used following the statement in the enclosing
block.</para>
<para>If you try to use a class that is not imported without its
fully-qualified name, the BeanShell interpreter will complain with an
error message relating to the offending line of code.</para>
<sidebar>
<para>Here is the full list of packages automatically imported by
jEdit:</para>
<programlisting>java.awt
java.awt.event
java.net
java.util
java.io
java.lang
javax.swing
javax.swing.event
org.gjt.sp.jedit
org.gjt.sp.jedit.browser
org.gjt.sp.jedit.buffer
org.gjt.sp.jedit.gui
org.gjt.sp.jedit.help
org.gjt.sp.jedit.io
org.gjt.sp.jedit.msg
org.gjt.sp.jedit.options
org.gjt.sp.jedit.pluginmgr
org.gjt.sp.jedit.print
org.gjt.sp.jedit.search
org.gjt.sp.jedit.syntax
org.gjt.sp.jedit.textarea
org.gjt.sp.util</programlisting>
</sidebar>
</section>
<section id="predefined-variables">
<title>Predefined Variables in BeanShell</title>
<para>The following variables are always available for use in BeanShell
scripts:</para>
<itemizedlist>
<listitem>
<para><varname>buffer</varname> - a <ulink
url="../api/org/gjt/sp/jedit/Buffer.html">Buffer</ulink> object
represents the contents of the currently visible open text
file.</para>
</listitem>
<listitem>
<para><varname>view</varname> - A <ulink
url="../api/org/gjt/sp/jedit/View.html">View</ulink> represents
the current top-level editor window, extending Java's
<classname>JFrame</classname> class, that contains the various
visible components of the program, including the text area, menu
bar, toolbar, and any docked windows.</para>
<para>This variable has the same value as the return value
of:</para>
<programlisting>jEdit.getActiveView()</programlisting>
</listitem>
<listitem>
<para><varname>editPane</varname> - an <ulink
url="../api/org/gjt/sp/jedit/EditPane.html">EditPane</ulink>
object contains a text area and buffer switcher. A view can be
split to display edit panes. Among other things, the <ulink
url="../api/org/gjt/sp/jedit/EditPane.html">EditPane</ulink>
class contains methods for selecting the buffer to edit.</para>
<para>Most of the time your macros will manipulate the
<varname>buffer</varname> or the <varname>textArea</varname>.
Sometimes you will need to use <varname>view</varname> as a
parameter in a method call. You will probably only need to use
<varname>editPane</varname> if your macros work with split
views.</para>
<para>This variable has the same value as the return value
of:</para>
<programlisting>view.getEditPane()</programlisting>
</listitem>
<listitem>
<para><varname>textArea</varname> - a <ulink
url="../api/org/gjt/sp/jedit/textarea/JEditTextArea.html">JEditTextArea</ulink>
is the visible component that displays the current
buffer.</para>
<para>This variable has the same value as the return value
of:</para>
<programlisting>editPane.getTextArea()</programlisting>
</listitem>
<listitem>
<para><varname>wm</varname> - a <ulink
url="../api/org/gjt/sp/jedit/gui/DockableWindowManager.html">DockableWindowManager</ulink>
is the visible component that manages dockable windows in the
current view. This class is discussed in detail in <xref
linkend="writing-plugins-part" />. This object is useful for
writing macros that interface with, open, or close plugin
windows.</para>
<para>This variable has the same value the return value
of:</para>
<programlisting>view.getDockableWindowManager()</programlisting>
</listitem>
<listitem>
<para><varname>scriptPath</varname> - set to the full path of
the script currently being executed.</para>
</listitem>
<listitem>
<para><varname>scriptPath</varname> - set to the full path of
the script currently being executed.</para>
</listitem>
</itemizedlist>
<para>Note that these variables are set at the beginning of macro
execution. If the macro switches views, buffers or edit panes, the
variable values will be out of date. In that case, you can use the
equivalent method calls.</para>
</section>
<section id="helpful-methods">
<title>Helpful Methods in the Macros Class</title>
<para>Including <function>message()</function>, there are five static
methods in the <ulink
url="../api/org/gjt/sp/jedit/Macros.html">Macros</ulink> class that
allow you to converse easily with your macros. They all encapsulate
calls to methods of the Java platform's
<classname>JOptionPane</classname> class.</para>
<itemizedlist>
<listitem>
<funcsynopsis>
<funcprototype>
<funcdef>public static void
<function>message</function></funcdef>
<paramdef>Component
<parameter>comp</parameter></paramdef>
<paramdef>String
<parameter>message</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</listitem>
<listitem>
<funcsynopsis>
<funcprototype>
<funcdef>public static void
<function>error</function></funcdef>
<paramdef>Component
<parameter>comp</parameter></paramdef>
<paramdef>String
<parameter>message</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</listitem>
<listitem>
<funcsynopsis>
<funcprototype>
<funcdef>public static String
<function>input</function></funcdef>
<paramdef>Component
<parameter>comp</parameter></paramdef>
<paramdef>String
<parameter>prompt</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</listitem>
<listitem>
<funcsynopsis>
<funcprototype>
<funcdef>public static String
<function>input</function></funcdef>
<paramdef>Component
<parameter>comp</parameter></paramdef>
<paramdef>String
<parameter>prompt</parameter></paramdef>
<paramdef>String
<parameter>defaultValue</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</listitem>
<listitem>
<funcsynopsis>
<funcprototype>
<funcdef>public static int
<function>confirm</function></funcdef>
<paramdef>Component
<parameter>comp</parameter></paramdef>
<paramdef>String
<parameter>prompt</parameter></paramdef>
<paramdef>int <parameter>buttons</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</listitem>
</itemizedlist>
<para>The format of these four <glossterm>declarations</glossterm>
provides a concise reference to the way in which the methods may be
used. The keyword <function>public</function> means that the method can
be used outside the <ulink
url="../api/org/gjt/sp/jedit/Macros.html">Macros</ulink> class. The
alternatives are <function>private</function> and
<function>protected</function>. For purposes of BeanShell, you just have
to know that BeanShell can only use public methods of other Java
classes. The keyword <function>static</function> we have already
discussed. It means that the method does not operate on a particular
object. You call a static function using the name of the class (like
<ulink url="../api/org/gjt/sp/jedit/Macros.html">Macros</ulink>) rather
than the name of a particular object (like <varname>view</varname>). The
third word is the type of the value returned by the method. The keyword
<function>void</function> is Java's way of saying the the method does
not have a return value.</para>
<para>The <function>error()</function> method works just like
<function>message()</function> but displays an error icon in the message
box. The <function>input()</function> method furnishes a text field for
input, an <guilabel>OK</guilabel> button and a
<guilabel>Cancel</guilabel> button. If <guilabel>Cancel</guilabel> is
pressed, the method returns <constant>null</constant>. If
<guilabel>OK</guilabel> is pressed, a <classname>String</classname>
containing the contents of the text field is returned. Note that there
are two forms of the <function>input()</function> method; the first form
with two parameters displays an empty input field, the other forms lets
you specify an initial, default input value.</para>
<para>For those without Java experience, it is important to know that
<constant>null</constant> is <emphasis>not</emphasis> the same as an
empty, <quote>zero-length</quote> <classname>String</classname>. It is
Java's way of saying that there is no object associated with this
variable. Whenever you seek to use a return value from
<function>input()</function> in your macro, you should test it to see if
it is <constant>null</constant>. In most cases, you will want to exit
gracefully from the script with a <function>return</function> statement,
because the presence of a null value for an input variable usually means
that the user intended to cancel macro execution. BeanShell will
complain if you call any methods on a <constant>null</constant>
object.</para>
<para>The <function>confirm()</function> method in the <ulink
url="../api/org/gjt/sp/jedit/Macros.html">Macros</ulink> class is a
little more complex. The <varname>buttons</varname> parameter has an
<classname>int</classname> type, and the usual way to supply a value is
to use one of the predefined values taken from Java's
<classname>JOptionPane</classname> class. You can choose among
<constant>JOptionPane.YES_NO_OPTION</constant>,
<constant>JOptionPane.YES_NO_CANCEL_OPTION</constant>, or
<constant>JOptionPane.OK_CANCEL_OPTION</constant>. The return value of
the method is also an <classname>int</classname>, and should be tested
against the value of other predefined constants:
<constant>JOptionPane.YES_OPTION</constant>,
<constant>JOptionPane.NO_OPTION</constant>,
<constant>JOptionPane.OK_OPTION</constant> or
<constant>JOptionPane.CANCEL_OPTION</constant>.</para>
<para>We've looked at using <function>Macros.message()</function>. To
use the other methods, you would write something like the
following:</para>
<informalexample>
<!-- <title>Using <function>Macros.error()</function> and
<function>Macros.input()</function></title> -->
<programlisting>Macros.error(view, "Goodbye, cruel world!");
String result = Macros.input(view, "Type something here.");
String result = Macros.input(view, "When were you born?",
"I don't remember, I was very young at the time");
int result = Macros.confirm(view, "Do you really want to learn"
+ " about BeanShell?",JOptionPane.YES_NO_OPTION);
</programlisting>
</informalexample>
<para>In the last three examples, placing the word
<classname>String</classname> or <classname>int</classname> before the
variable name <varname>result</varname> tells BeanShell that the
variable refers to an integer or a <classname>String</classname> object,
even before a particular value is assigned to the variable. In
BeanShell, this <glossterm>declaration</glossterm> of the
<glossterm>type</glossterm> of <varname>result</varname> is not
necessary; BeanShell can figure it out when the macro runs. This can be
helpful if you are not comfortable with specifying types and classes;
just use your variables and let BeanShell worry about it.</para>
<para>Note that macros are not limited to using these methods for
presenting a user interface. In fact, full-blown user interfaces using
the Java Swing APIs are also possible, and will be covered later on in
<xref linkend="dialog-macro" />.</para>
</section>
<section id="dynamic-typing">
<title>BeanShell Dynamic Typing</title>
<para>Without an explicit <glossterm>type declaration</glossterm> like
<classname>String</classname> <varname>result</varname>, BeanShell
variables can change their type at runtime depending on the object or
data assigned to it. This dynamic typing allows you to write code like
this (if you really wanted to):</para>
<informalexample>
<!-- <title>Dynamic typing of variables</title> -->
<programlisting>// note: no type declaration
result = Macros.input(view, <quote>Type something here.</quote>);
// this is our predefined, current View
result = view;
// this is an <quote>int</quote> (for integer);
// in Java and BeanShell, int is one of a small number
// of <quote>primitive</quote> data types which are not classes
result = 14;</programlisting>
</informalexample>
<para>However, if you first declared <varname>result</varname> to be
type <classname>String</classname> and and then tried these
reassignments, BeanShell would complain. While avoiding explicit type
declaration makes writing macro code simpler, using them can act as a
check to make sure you are not using the wrong variable type of object
at a later point in your script. It also makes it easier (if you are so
inclined) to take a BeanShell <quote>prototype</quote> and incorporate
it in a Java program.</para>
<para>One last thing before we bury our first macro. The double slashes
in the examples just above signify that everything following them on
that line should be ignored by BeanShell as a comment. As in Java and
C/C++, you can also embed comments in your BeanShell code by setting
them off with pairs of <userinput>/* */</userinput>, as in the following
example:</para>
<informalexample>
<programlisting>/* This is a long comment that covers several lines
and will be totally ignored by BeanShell regardless of how
many lines it covers */</programlisting>
</informalexample>
</section>
<section id="something-useful">
<title>Now For Something Useful</title>
<para>Here is a macro that inserts the path of the current buffer in the
text:</para>
<informalexample>
<!-- <title>Insert buffer path in text</title> -->
<programlisting>String newText = buffer.getPath();
textArea.setSelectedText(newText);</programlisting>
</informalexample>
<para>Unlike in our first macro example, here we are calling class
methods on particular objects. First, we call
<function>getPath()</function> on the current <ulink
url="../api/org/gjt/sp/jedit/Buffer.html">Buffer</ulink> object to get
the full path of the text file currently being edited. Next, we call
<function>setSelectedText()</function> on the current text display
component, specifying the text to be inserted as a parameter.</para>
<para>In precise terms, the <function>setSelectedText()</function>
method substitutes the contents of the <classname>String</classname>
parameter for a range of selected text that includes the current caret
position. If no text is selected at the caret position, the effect of
this operation is simply to insert the new text at that position.</para>
<para>Here's a few alternatives to the full file path that you could use
to insert various useful things:</para>
<informalexample>
<!-- <title>Items to use with
<function>setSelectedText()</function></title> -->
<programlisting>// the file name (without full path)
String newText = buffer.getName();
// today's date
import java.text.DateFormat;
String newText = DateFormat.getDateInstance()
.format(new Date());
// a line count for the current buffer
String newText = "This file contains "
+ textArea.getLineCount() + " lines.";</programlisting>
</informalexample>
<para>Here are brief comments on each:</para>
<itemizedlist>
<listitem>
<para>In the first, the call to <function>getName()</function>
invokes another method of the <ulink
url="../api/org/gjt/sp/jedit/Buffer.html">Buffer</ulink>
class.</para>
</listitem>
<listitem>
<para>The syntax of the second example chains the results of
several methods. You could write it this way:</para>
<programlisting>import java.text.DateFormat;
Date d = new Date();
DateFormat df = DateFormat.getDateInstance();
String result = df.format(d);
</programlisting>
<para>Taking the pieces in order:</para>
<itemizedlist>
<listitem>
<para>A Java <classname>Date</classname> object is
created using the <function>new</function> keyword. The
empty parenthesis after <classname>Date</classname>
signify a call on the <glossterm> constructor
method</glossterm> of <classname>Date</classname> having
no parameters; here, a <classname>Date</classname> is
created representing the current date and time.</para>
</listitem>
<listitem>
<para><function>DateFormat.getDateInstance()</function>
is a static method that creates and returns a
<classname>DateFormat</classname> object. As the name
implies, <classname>DateFormat</classname> is a Java
class that takes <classname>Date</classname> objects and
produces readable text. The method
<function>getDateInstance()</function> returns a
<classname>DateFormat</classname> object that parses and
formats dates. It will use the default
<glossterm>locale</glossterm> or text format specified
in the user's Java installation.</para>
</listitem>
<listitem>
<para>Finally,
<classname>DateFormat.format()</classname> is called on
the new <classname>DateFormat</classname> object using
the <classname>Date</classname> object as a parameter.
The result is a <classname>String</classname> containing
the date in the default locale.</para>
</listitem>
<listitem>
<para>Note that the <classname>Date</classname> class is
contained in the <literal>java.util</literal> package,
so an explicit import statement is not required.
However, <classname>DateFormat</classname> is part of
the <literal>java.text</literal> package, which is not
automatically imported, so an explicit
<function>import</function> statement must be
used.</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>The third example shows three items of note: <itemizedlist>
<listitem>
<para><function>getLineCount()</function> is a method
in jEdit's <ulink
url="../api/org/gjt/sp/jedit/textarea/JEditTextArea.html">JEditTextArea</ulink>
class. It returns an <classname>int</classname>
representing the number of lines in the current text
buffer. We call it on <varname>textArea</varname>,
the pre-defined, current <ulink
url="../api/org/gjt/sp/jedit/textarea/JEditTextArea.html">JEditTextArea</ulink>
object.</para>
</listitem>
<listitem>
<para>The use of the <function>+</function> operator
(which can be chained, as here) appends objects and
string literals to return a single, concatenated
<classname>String</classname>.</para>
</listitem>
</itemizedlist></para>
</listitem>
</itemizedlist>
</section>
</chapter>
|