This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
About the Author John Hurst has been programming computers for fun and profit since he was 14. He started with BASIC on a home computer and then moved on to Pascal and C. He has worked with many other languages since, and today works mostly with Java and Ruby. He is an independent consultant/developer and provides design, development and training services to companies in New Zealand and Australia. You can find out about John on his website at http:// www.skepticalhumorist.co.nz. John lives in Wellington, New Zealand, with his partner, Zena, and their two children, Rose and Oliver.
22150ffirs.qxd:WroxPro
9/25/07
12:12 AM
Page x
22150ffirs.qxd:WroxPro
9/25/07
12:12 AM
Page xi
Credits Acquisitions Editor
Compositor
Chris Webb
Kate Kaminski, Happenstance Type-O-Rama
Development Editor
Proofreader
Kenyon Brown
Nancy Carrasco
Technical Editor
Indexer
Mark Berger
Melanie Belkin
Production Editor
Project Coordinator, Cover
Debra Banninger
Lynsey Osborn
Copy Editor
Media Development Project Supervisor
Cate Caffrey
Laura Atkinson
Editorial Manager
Media Development Specialist
Mary Beth Wakefield
Angie Denny
Production Manager
Media Quality Assurance
Tim Tate
Kit Malone
Vice President and Executive Group Publisher
Anniversary Logo Design
Richard Swadley
Richard Pacifico
Vice President and Executive Publisher Joseph B. Wikert
22150ffirs.qxd:WroxPro
9/25/07
12:12 AM
Page xii
22150ffirs.qxd:WroxPro
9/25/07
12:12 AM
Page xiii
Acknowledgments I’ve read that writing a book is harder than writing software. It certainly seems harder, and it is not as much fun. But, if writing is not as much fun, reviewing must be even worse. Nevertheless, my friend and colleague Mark Berger has devoted himself thoroughly to this project, checking everything carefully and pointing out many errors. If you do find errors in the book, they were added by me after Mark had finished his job. Mark has also provided stimulus throughout my career, being well informed and passionate about software development tools and practices. My thoughts about programming and software systems have been refined continuously through many discussions with Mark over the years. The team at SlickEdit should be proud to have created one of the most useful and enduring software tools ever made. They continue to refine and enhance it every year, and during 2007 their release schedule overlapped the writing of this book for the most part. All the same, they made time to support me in writing this book, by providing early builds, explaining features, and reviewing material. It was a great privilege to talk to several SlickEdit developers and discuss SlickEdit and the book with them. Most of the SlickEdit team has made a contribution to this book in one form or another, many through providing tips and assistance on the SlickEdit Community Forums. I thank Clark Maurer, Dan Henry, Dennis Brueni, Lee Baldwin, Lisa Rodwell, Matthew Etter, Mike Cohen, Rodney Bloom, Ryan Huff, Sandra Gaskin, Scott Hackett, Scott Westfall, and the other folks at SlickEdit for all their help. Scott Westfall, in particular, reviewed every chapter and contributed material on Workspaces and Projects for Chapter 4. Dan Henry, Dennis Brueni, Lisa Rodwell, Rodney Bloom, and Sandra Gaskin reviewed chapters and contributed feedback. Rodney contributed code samples. Dennis contributed code samples, and also the troubleshooting checklist for Context Tagging in Chapter 5. Hartmut Schaefer, aka “hs2,” is an outstanding member of the SlickEdit online community. He has posted hundreds of posts in the Community Forums, answering questions, suggesting improvements, and finding (and fixing) bugs. Several of hs2’s tips appear in this book. Thanks for everything, hs2. Other community members have also provided material online that helped this book. Graeme Prentice made several useful suggestions relating to forms and GUI elements. Graeme is a frequent contributor to the online forums. Ding Zhaojie also posts bug fixes and improvements, some of which have directly assisted me in writing this book. Dierk König wrote Groovy in Action (Manning, 2007), from which I’ve adapted his technique for illustrating code snippets using unit testing assertions. Kenyon Brown, the Development Editor for this book, put up with a lot of annoying questions from a novice author. He also moved the book through the writing process, doing what he could to keep me focused and on schedule.
22150ffirs.qxd:WroxPro
9/25/07
12:12 AM
Page xiv
Acknowledgments Cate Caffrey, the Copy Editor, has made me realize that I ought to go back to school and learn English. I own several books on clear writing and good English usage (more awkwardly, “a number of” them). However, the fact of ownership has done little to improve my own usage. If any sentence of this book reads well, it is largely thanks to Cate. I’d like to thank Chris Webb, Executive Editor at Wiley, for finding me and giving me this opportunity. Chris has been wonderfully supportive (and persuasive). I also thank the management at the client where I currently do most of my work, Red Energy in Melbourne, Australia. Lucy Aston and Steve Byrne have put together a great team and a great work environment, and I’m grateful that they were so understanding and supportive of this project. There is never any shortage of work to do at a startup, and I hope I can catch up on all the things I have neglected the last few weeks. Unfortunately, I think Lucy will be disappointed with this book, since it is rather dry and humorless. Wait until you see the movie though. My mother bought me my first computer, many years ago. But she’s pretty smart, and before she got the computer, she gave me a book about computer programming. I think I had read the whole book at least once before I got the computer. My partner, Zena, has a ThinkGeek T-shirt that says “I love my geek,” and I have to believe it. She’s been wonderful, always. Maybe she can write the next book, about something other than computers.
xiv
22150ftoc.qxd:WroxPro
9/25/07
12:13 AM
Page xv
Contents Acknowledgments Introduction
xiii xxv
Part I: Getting Started with SlickEdit
1
Chapter 1: Introducing SlickEdit
3
Programmers Edit Code Power Editing with SlickEdit SlickEdit As a Development Environment Multiple Platforms Customizable Extensible: Slick-C
This Book SlickEdit Terminology Overview of Interface The Build Tool Window
Macros Recording a Macro Writing a Macro Loading a Macro Supplied Macro Source
Summary
Chapter 2: Configuration Emulations and Key Bindings The ‘WROX’ Emulation Alt Keys
3 4 5 5 5 6
6 7 7 9
9 10
11 12 13
14 14 16 17 18
18
19 19 21 21
22150ftoc.qxd:WroxPro
9/25/07
12:13 AM
Page xvi
Contents Macro Variables Using the Set Variable Dialog Using the set-var Command
22 22 23
Common Settings
24
Appearance Fonts Line Behavior
24 25 26
Managing Configurations Configuration Directory Reverting to the Default Configuration Working with a Different Configuration
Summary
Chapter 3: Managing Windows Windows and Buffers Split Windows Full Screen Toolbars Tool Windows Tool Window Arrangement Activating Tool Windows with the Keyboard Tool Window Animation Restoring the Defaults
Summary
30 30 30 31
32
33 34 34 35 35 35 36 38 40 40
40
Part II: Using SlickEdit
41
Chapter 4: Workspaces and Projects
43
How to Organize Your Files The Example Creating a GNU C/C++ Project
45 46 47
Creating the Project Building the Project Executing the Project Adding Unit Tests Target Configurations Build Systems
49 52 53 54 60 60
Creating a Java Project
61
Creating the Project
61
xvi
22150ftoc.qxd:WroxPro
9/25/07
12:13 AM
Page xvii
Contents Building the Project Executing the Project Adding Unit Tests Managing the Project with Ant
Creating a Project for a Dynamic Language Creating the Project Executing the Project Adding Unit Tests
Custom Projects Summary
Chapter 5: Context Tagging Setting Up for Tagging Tagging Your Workspace Tagging Built-in and Standard Libraries
Listing Members Configuring List Members
Getting Parameter Information Configuring Parameter Information
61 62 62 65
65 66 66 67
70 72
73 74 74 74
76 78
78 80
Navigating with Symbols
81
The Preview Tool Window Navigating to Definitions Navigating to References Pushed Bookmarks
81 81 82 83
Finding Symbols The Find Symbol Tool Window Using the grep-tag command
Browsing Definitions The Defs Tool Window The Class Tool Window The Symbols Tool Window
Managing Tag Files Global Tag Databases Auto-Updated Tag Databases Tagging Dynamic Languages Tagging C/C++ Libraries Tagging Java Libraries Tagging .NET Runtime Libraries
The C/C++ Preprocessor Troubleshooting Tagging Go to Definition Doesn’t Work
84 84 85
85 85 86 87
88 89 90 90 92 98 102
104 105 105
xvii
22150ftoc.qxd:WroxPro
9/25/07
12:13 AM
Page xviii
Contents Go to Reference Doesn’t Work Auto-List Members Doesn’t Work Auto-Parameter Information Doesn’t Work Solution A: Define C/C++ Preprocessing Solution B: Add Symbol to Tag File Solution C: Configure C/C++ Extensionless Header Files Solution D: Create a File Extension Alias Solution E: Rebuild Your Tag File(s)
107 107 107 107 108 108 109 109
Performance Tuning
109
Tuning Maximums Tag Cache Size References Complex Code
110 111 111 111
Summary
Chapter 6: Navigation Finding and Opening Files Using File Open Using File and Directory Aliases Using the edit Command Using Tool Windows Using the File Manager Navigating to Header Files
Moving Around Navigating in the buffer Positioning the Window Navigating to a Line, Column, or Byte Offset Navigating among Buffers
Bookmarks Pushed Bookmarks Named Bookmarks Configuring Bookmarks
Summary
Chapter 7: Search and Replace Keyboard Searching Terminating a Long Search Quick Search Incremental Search
xviii
112
113 114 114 116 117 117 119 119
119 120 123 124 125
127 127 128 129
130
131 131 132 132 132
22150ftoc.qxd:WroxPro
9/25/07
12:13 AM
Page xix
Contents The Find and Replace Tool Window Using Find Using Find in Files Using Replace and Replace in Files
Working with the Clipboard Locked Selections Selection Models Special Selection Commands Working with Selections Using Selection Scopes Saving and Reusing Selections Configuring Selection Options
153 155 157 160 161 162 163 164
Saving Typing with Word Completion Introduction to Word Completion Word Completion in Programming Options with Word Completion
Summary
Chapter 9: Editing Code File Extensions, Modes, and Lexers
165 165 168 169
171
173 173
Extensionless Files
175
Syntax Highlighting
175
xix
22150ftoc.qxd:WroxPro
9/25/07
12:13 AM
Page xx
Contents Indentation and Code Style C/C++ Options Java and C# Options HTML Options Other Languages
Working with Control Structures Syntax Expansion Adding a Control Structure Dynamic Surround Deleting a Control Structure Avoiding Syntax Assistance
Unified Completions with Auto-Complete Introduction to Auto-Complete Auto-Complete in Programming Configuring Auto-Complete Manual Completion or Auto-Complete?
Embedded Languages Web Programming ‘Here Documents’ in Scripts
178 179 180 180
180 181 182 183 184 185
186 186 188 189 190
190 190 191
Working with Comments
192
Line Comments Multiline Comments JavaDoc Comments Configuring Comments
193 194 195 195
Summary
Chapter 10: Editing Data Block Selection Moving, Copying, and Deleting with Block Selections Navigating Block Selections
197
199 200 200 202
Entering Data in Columns
202
Filling Data Using Block Insert Mode
203 203
Sorting Data Generating Data Calculating with Data Manipulating Data Block Editing Macro Record and Playback Search and Replace with Data
xx
177
204 205 206 207 208 213 220
22150ftoc.qxd:WroxPro
9/25/07
12:13 AM
Page xxi
Contents Aligning Data Large Data Files Summary
Chapter 11: Aliases and File Templates Aliases File Aliases Using Aliases in Code Dynamic Directory Aliases Extension-Specific Aliases Syntax Expansion with Aliases Surround Aliases Aliases with Parameters Aliases and Configuration
File Templates Instantiating a Template Creating a Template Substitution Parameters Managing Templates Instantiating Templates in Macros
Summary
Chapter 12: Document Types Document Mode Binary Files Character Sets and Encodings XML Document Types Summary
Chapter 13: Comparing and Merging Comparing Files and Directories Comparing Two Files Comparing Sections within a File Comparing Directories DIFFzilla Options Running DIFFzilla Standalone
Merging Changes Backup History Summary
222 226 227
229 229 230 232 234 235 237 238 239 240
241 241 242 246 248 248
252
253 253 254 254 255 258
259 259 260 262 265 266 266
266 269 270
xxi
22150ftoc.qxd:WroxPro
9/25/07
12:13 AM
Page xxii
Contents Chapter 14: Version Control CVS Using an Existing Working Copy Checking Out an Existing Project Reviewing Changes Adding Files Committing Changes Merge Conflicts Using Commit Sets to Group Changes Branches and Tags Browsing the History Keyboard Bindings
Subversion Configuring SlickEdit for Subversion Creating a New Project Checking Out a Working Copy Reviewing and Committing Changes, Adding Files Merge Conflicts Branches and Tags Browsing the History Keyboard Bindings
Summary
Part III: Advanced SlickEdit Chapter 15: Other Tools The File Manager File Manager Commands Selecting Files Automating Tasks
FTP/SSH for Remote Editing The FTP Client Using HTTP To Open Web Pages
The Regex Evaluator Summary
Chapter 16: Slick-C Macro Programming The Slick-C Language Modules and Names
xxii
271 271 272 274 275 277 278 278 279 282 283 284
285 287 287 288 289 289 290 291 292
293
295 297 298 299 300 301
302 304 305
305 306
307 308 309
22150ftoc.qxd:WroxPro
9/25/07
12:13 AM
Page xxiii
Contents Preprocessor Functions Properties Data Types Control Structures Declarations and Definitions
Working with Macros Executing Slick-C Code Terminating a Macro Writing Messages Stack Traces Finding Slick-C Objects
Useful Techniques Interacting with the Buffer Searching Selections Temporary Buffers Listing Files and Directories Choosing Files Useful Macro Files Callbacks
Example Macros Example: Example: Example: Example: Example: Example:
Counting Duplicate Lines Inserting HTML End Tag Moving Lines Up and Down Callback Traces WROX Function Names N-Queens
System Requirements Using the CD with Windows Using the CD with Linux and UNIX Using the CD with the Mac OS What’s on the CD
445 447 447 448 448
Author-Created Materials Applications
448 449
Troubleshooting
449
Customer Care
449
Index
xxiv
451
22150flast.qxd:WroxPro
9/25/07
12:15 AM
Page xxv
Introduction I have been using SlickEdit almost every day for more than 10 years. For most of that time, it has been my editor of choice for almost every programming language I’ve used. I strongly believe that a really powerful and versatile programming editor is the most important tool that a professional programmer uses. I’m dismayed sometimes when I see programmers using IDEs ineffectively or producing substandard code because of limitations in their development environment. I wrote this book to help you get the most out of SlickEdit. I hope you enjoy it.
Who’s the Book For? This book is intended for experienced programmers. You are more than comfortable with computers. You do not need to be told how to install simple software packages, or how to navigate your directory tree to open a file, or how to select text with a mouse. You should have a preference for using the keyboard rather than the mouse, for tasks you do regularly. If you are using SlickEdit, you almost certainly have experience in other programming environments, and you probably program in more than one language, perhaps on more than one platform. On the other hand, SlickEdit is not about any particular programming language.
What’s Covered in the Book? SlickEdit is a very feature-rich product. This book does not attempt to document every feature. The SlickEdit User Guide that is shipped with the product does not even document every feature, and it is longer than this book! Instead, this book covers techniques and strategies to make the most of SlickEdit. I hope that, by reading this book, you will learn about one or two (at least!) nice features you didn’t know about. But more importantly, if you are new to SlickEdit or haven’t explored it in detail, I hope you will learn some ways of making it work effectively for you. It would be hard to guess which programming languages and environments are most common among SlickEdit users, since SlickEdit works well with all programming languages and most operating systems. SlickEdit has many features that support certain programming languages, but I personally feel that its feature set for C/C++ is the strongest. Nevertheless, in this book, we will not be focusing very much on particular languages. SlickEdit supports compiling running and debugging programs in C/C++ and other languages, but we won’t concentrate on those aspects. Instead, we’re going to focus mainly on editing and related tasks, and also on how you can customize and extend SlickEdit to meet your needs, regardless of what programming language you are using. Most of the information in this book should apply to all programming languages. If you don’t find examples in the language you’re using, you should still find the techniques useful.
22150flast.qxd:WroxPro
9/25/07
12:15 AM
Page xxvi
Introduction This book is not a substitute for the online Help and other reference documentation that comes with SlickEdit. The online Help system contains detailed information organized around the features and is comprehensive and up-to-date. When we discuss features in this book, we will often give one or more examples of typical use. In some cases, we’ll discuss options and strategies for the feature in detail, but in other cases you will be referred to the online Help for more information. I debated with myself about including so many screen shots of dialogs. In some ways they’re redundant too, since they are all covered in the online Help and you can bring up the dialogs easily enough for yourself. However, I’ve found that with so many options, and so many dialogs, there are probably a few of them you won’t have noticed, or won’t have come across during your ordinary use of SlickEdit. Also, sometimes just seeing the options that are available in the dialogs can tell you, at a glance, something about the features available.
Conventions To help you get the most from the text and keep track of what’s happening, we’ve used a number of conventions throughout the book. Boxes like this one hold important, not-to-be forgotten information that is directly relevant to the surrounding text.
Tips, hints, tricks, and asides to the current discussion are offset and placed in italics like this. As for styles in the text: ❑
We highlight new terms and important words when we introduce them.
❑
We show keyboard strokes like this: Ctrl+A.
❑
We show filenames, URLs, and code within the text like so: persistence.properties.
❑
We present code in two different ways: In code examples we highlight important code in bold
Source Code As you work through the examples in this book, you may choose either to type in all the code manually or to use the source code files that accompany the book. All of the source code used in this book is available for download at http://www.wrox.com. Once at the site, simply locate the book’s title (either by using the Search box or by using one of the title lists), and click the Download Code link on the book’s detail page to obtain all the source code for the book. Because many books have similar titles, you may find it easiest to search by ISBN; this book’s ISBN is 978-0-470-12215-0.
xxvi
22150flast.qxd:WroxPro
9/25/07
12:15 AM
Page xxvii
Introduction Once you download the code, just decompress it with your favorite compression tool. Alternately, you can go to the main Wrox code download page at http://www.wrox.com/dynamic/books/download.aspx to see the code available for this book and all other Wrox books.
Errata We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you find an error in one of our books, like a spelling mistake or faulty piece of code, we would be very grateful for your feedback. By sending in errata you may save another reader hours of frustration, and at the same time you will be helping us provide even higher quality information. To find the errata page for this book, go to http://www.wrox.com, and locate the title using the Search box or one of the title lists. Then, on the Book Details page, click the Book Errata link. On this page you can view all errata that have been submitted for this book and posted by Wrox editors. A complete book list including links to each book’s errata is also available at http://www.wrox.com/misc-pages/booklist.shtml. If you don’t spot “your” error on the Book Errata page, go to http://www.wrox.com/contact/ techsupport.shtml, and complete the form there to send us the error you have found. We’ll check the information and, if appropriate, post a message to the book’s errata page and fix the problem in subsequent editions of the book.
p2p.wrox.com For author and peer discussion, join the P2P forums at http://p2p.wrox.com. The forums are a Webbased system for you to post messages relating to Wrox books and related technologies and interact with other readers and technology users. The forums offer a subscription feature to e-mail you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums. At http://p2p.wrox.com, you will find several different forums that will help you not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps:
1. 2. 3.
Go to http://p2p.wrox.com, and click the Register link.
4.
You will receive an e-mail with information describing how to verify your account and complete the joining process.
Read the Terms of Use, and click Agree. Complete the required information to join as well as any optional information you wish to provide, and click Submit.
You can read messages in the forums without joining P2P, but in order to post your own messages, you must join.
xxvii
22150flast.qxd:WroxPro
9/25/07
12:15 AM
Page xxviii
Introduction Once you join, you can post new messages and respond to messages other users post. You can read messages at any time on the Web. If you would like to have new messages from a particular forum e-mailed to you, click the Subscribe to This Forum icon by the forum name in the forum listing. For more information about how to use the Wrox P2P, be sure to read the P2P FAQs for answers to questions about how the forum software works as well as many common questions specific to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page.
xxviii
22150flast.qxd:WroxPro
9/25/07
12:15 AM
Page xxix
Professional
SlickEdit®
22150flast.qxd:WroxPro
9/25/07
12:15 AM
Page xxx
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 1
Part I: Getting Started with SlickEdit Chapter 1: Introducing SlickEdit Chapter 2: Configuration Chapter 3: Managing Windows
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 2
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 3
Introducing SlickEdit Welcome to SlickEdit, a text editor for programmers. In this first chapter, I start by telling you something about what makes SlickEdit so good, and why I think it is one of the best programming tools around. In the remainder of the chapter, we cover some of the central concepts of SlickEdit, which we use throughout the rest of the book.
Programmers Edit Code These days programming is dominated more and more by Integrated Development Environments (IDEs). IDEs can be very useful and productive in many situations. They tend to emphasize certain aspects of the development process such as setting up projects, organizing code, and debugging. Many tasks in IDEs are done with wizards, which lead the user through a process, collecting information to complete a task. Software development does involve a lot of different activities. It’s important to use tools that make your workflow smooth and efficient. But the focus on wizards and other bells and whistles in IDEs misses an important point. Despite all these other activities, the single thing programmers spend most of their time doing is editing code. In his book Code Complete (2nd ed., Microsoft Press, 2004), Steve McConnell cites evidence that some programmers estimate they spend “as much as 40 percent of their time editing source code.” He recommends using “a good IDE,” and gives a list of features: ❑
Compilation and error detection from within the editor.
❑
Integration with source-code control, build, test, and debugging tools.
❑
Compressed or outline views of programs.
❑
Jump to definitions of classes, routines, and variables.
❑
Jump to all places where a class, routine, or variable is used.
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 4
Part I: Getting Started with SlickEdit ❑
Language-specific formatting.
❑
Interactive help for the language being edited.
❑
Brace (begin-end) matching.
❑
Templates for common language constructs.
❑
Smart indenting.
❑
Automated code transforms or refactorings.
❑
Macros programmable in a familiar programming language.
❑
Listing of search strings so that commonly used strings don’t need to be retyped.
❑
Regular expressions in search and replace.
❑
Search and replace across a group of files.
❑
Editing multiple files simultaneously.
❑
Side-by-side diff comparisons.
❑
Multilevel undo.
McConnell adds, “Considering some of the primitive editors still in use, you might be surprised to learn that several editors include all these capabilities.” SlickEdit is one of those editors. SlickEdit provides all the features in McConnell’s list, to some degree, and more. However, it is not just about features. Some of these features are about the workflow of developing software: compiling, debugging, source code control, and so on. IDEs typically do these things fairly well. Where SlickEdit really comes out on top is in editing code. Most IDEs’ editors, although they may have a lot of fancy features such as toolbars and Class Wizards and so forth, are simply not advanced editors. They make you type and click too much. Then there is the problem that most IDEs are only good for a single programming language or environment. Many programmers need to work in a lot of different environments, and it is frustrating and inefficient to use a different editor for each one.
Power Editing with SlickEdit In The Pragmatic Programmer (Addison-Wesley, 1999), Andrew Hunt and Dave Thomas devote a section to “Power Editing.” They summarize their position as “Use a Single Editor Well.” They list several environment-specific features it is desirable for an editor to have, such as syntax highlighting, autocompletion, and autoindentation. But more important than any such specific features, they outline three “basic abilities we think every decent editor should have”: ❑
4
Configurable — All aspects of the editor should be configurable to your preferences, including fonts, colors, window sizes, and keystroke bindings (which keys perform what commands). Using only keystrokes for common editing operations is more efficient than mouse or menudriven commands, because your hands never leave the keyboard.
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 5
Chapter 1: Introducing SlickEdit ❑
Extensible — An editor shouldn’t be obsolete just because a new programming language comes out. It should be able to integrate with whatever compiler environment you are using. You should be able to “teach” it the nuances of any new language or text format (XML, HTML version 9, etc.).
❑
Programmable — You should be able to program the editor to perform complex, multistep tasks. This can be done with macros or with a built-in scripting language (Emacs uses a variant of Lisp, for instance).
These abilities are at the center of SlickEdit’s philosophy and design.
SlickEdit As a Development Environment IDEs tend to be targeted at specific programming platforms and specific development processes. They automate a variety of standard tasks with wizards and other tools. They can be very productive if you are comfortable working the “IDE’s way.” SlickEdit has a lot of overlap with IDEs. It also provides support for a lot of IDE-type features: building, running, and debugging programs. The main focus of SlickEdit is a little different though. Rather than focusing on a particular programming platform, SlickEdit places the emphasis on editing and navigating code. The SlickEdit philosophy is that programmers spend most of their time writing code, and SlickEdit aims to make that as fast and productive as possible. SlickEdit is fast. IDEs get loaded up with more and more features. Many of them are useful, but they all come at a price. How long does it take the IDE to open a file? How responsive is it while typing in code? Many IDEs have so many “intelligent” features that they spend a lot of time thinking while you’re trying to type in code. SlickEdit is always responsive.
Multiple Platforms SlickEdit is not tied to a particular programming platform. Most of its features are generic and apply equally well to any programming language or platform. On top of that, it does provide IDE-like tools and language-specific support for many popular programming languages. SlickEdit is also not tied to an operating system. I started using SlickEdit on OS/2, but I’ve also owned copies for Windows, AIX, and GNU/Linux. Virtually all the functionality is the same. Just as importantly, the customizations and macros I’ve done while using one operating system have all been carried through to other operating systems. I don’t have to learn a whole new tool and create a whole new set of customizations, just because I am switching from Windows to GNU/Linux for a project.
Customizable SlickEdit is very customizable. Out of the box, SlickEdit provides “emulations” for more than a dozen popular editors. These emulations provide a basic starting point for the behavior of the editor. Virtually every aspect of the editor can be customized. Don’t like the way the Enter key moves to the next line? You can change it. Don’t like the indentation or brace style? You can change them.
5
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 6
Part I: Getting Started with SlickEdit Many configuration settings are available as settings in the extensive configuration dialogs. Others are controlled by environment and “macro” variables. But it doesn’t stop there. Beyond configuration, SlickEdit is also very extensible. Many Integrated Development Environments (IDEs) are extensible to some degree. These days, “plug-ins” are a popular way to extend IDEs. But in most cases, the plug-in system is relatively complex, with a steep learning curve before anything useful can be achieved. Because most plug-ins require a considerable amount of work, plug-ins are generally used for significant add-on modules only.
Extensible: Slick-C You can customize and extend SlickEdit using Slick-C, a macro, or scripting language. One of the most important goals in this book is to introduce you to Slick-C and show you how easy it is to use it to customize or extend SlickEdit. Slick-C is easier to use than most plug-in systems. Slick-C is named after C and derives many of its features from C, such as control structures and declaration style. But Slick-C is really more of a scripting language. It is remarkably easy to learn and to use and is much more productive to code in than C. So if you’re not a C programmer, or you don’t like C, don’t worry. Even if it sounds too hard for you, try it! You will be surprised. Many of SlickEdit’s features are implemented in Slick-C. The complete source code for those features is provided with the product, more than 750,000 lines of it at last count! Having the source code to such a major part of SlickEdit’s functionality makes using it a lot like using an open-source product. If you’ve worked with open-source libraries or tools, you probably know how useful it is to be able to dive into the source code. You can often use features more effectively if you know how they really work. You can extend or alter features if they don’t fit your needs. You can write your own features. And, sometimes, you may even find a bug and see how to fix it. All of these benefits apply to SlickEdit and its supplied Slick-C source code, even though SlickEdit is a commercial product. This book aims to explain some details about macro programming and provides many useful examples you can use or adapt to your own needs. As we discover features of SlickEdit, we will often show examples of how they can be used or extended with Slick-C. The last two chapters of the book go into Slick-C in depth and show detailed examples of customization. But, as we mentioned already, the main point is to show you how easy it is and to get you started on your own macros.
This Book SlickEdit is a powerful and versatile programming editor. Much of its power comes from its design and the large number of features that are included. Some important features are very simple, like being fast to edit and navigate even very large files. Some features are advanced and specific, such as syntax assistance for various programming languages. We will be covering a lot of these features throughout this book. However, most of these features are already covered pretty well in the User Guide and Online Help shipped with the product. This book is not a reference manual and is not intended to replace the user guide. While we will cover some details of many of the features, we will focus more on general capabilities and the versatility of SlickEdit.
6
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 7
Chapter 1: Introducing SlickEdit This book is written from my own perspective. I was a C++ programmer when I started with SlickEdit, and C/C++ programming is perhaps SlickEdit’s strongest area. But I’m not a C/C++ programmer now, and I have not used SlickEdit for C or C++ for quite some time. I don’t know the details of many aspects of C/C++ features in SlickEdit, and we won’t be covering those features. For example, SlickEdit has debugger integration, but we don’t cover that at all in this book. Although SlickEdit is available for many different operating systems, Windows is probably the most common. The screen shots in this book are almost all taken on Windows. In most cases, the discussion should apply to all operating systems equally well, but in some cases there are differences. For example, Macs use different keyboards from most computers, thus the discussion of Alt key bindings in Chapter 2 does not work with Macs. The current version of SlickEdit at the time of this writing is 12.0.2, which was released in July 2007. The “12.x” series of SlickEdit is marketed as “SlickEdit 2007.” Most of this book was written using SlickEdit 12.0.0 and 12.0.1 for examples. Naturally, things change from version to version. I hope that most of the material in this book will remain useful and relevant through future versions of SlickEdit, but without doubt some changes in future versions will be incompatible with information presented here. Updates to macro sources will be placed online.
SlickEdit Terminolog y Before we start to look at SlickEdit concepts, we should get a few terms straight. When you open a file in SlickEdit, the file is loaded into a buffer. The buffer is the in-memory representation of the file. The buffer has the same name as the physical file. Changes to the buffer are saved to disk when you save the file. Sometimes the terms file and buffer are used interchangeably. The buffer is displayed in a window. The window is the GUI view of the buffer. In the default configuration, there is one window created for each buffer. We talk about managing windows in more detail in Chapter 3. In this book, while explaining certain dialogs, we use phrases such as “Click OK to dismiss the Project Properties dialog.” Most of the time, of course, you will not actually click OK; rather, you will simply press Enter, because OK is the default button. However, we stick to the “Click” terminology most of the time, because it is commonly used in help and user guides, and it makes it clear which dialog control we really mean. After all, if you tab around, the focus might change to a control where the Enter key is not the same as clicking OK.
Over view of Interface Figure 1-1 shows the SlickEdit user interface. The main part of the window is the editing pane. Below the editing pane is the File Tabs toolbar, showing the open files. SlickEdit has several other toolbars, not shown. Toolbar functions are generally invoked using the mouse, and in most cases it is a lot faster and easier to use the keyboard, rather than the mouse.
7
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 8
Part I: Getting Started with SlickEdit
Figure 1-1
Many computer users use the mouse a lot. The mouse is a great way to learn a program. When you first start using a program, you use the mouse to browse around. It’s kind of like browsing the Web: You’re just looking around; you aren’t really doing anything. Once you start really using a program to do things, you tend to find you’re doing some things a lot. For those things, you will do them a lot faster using the keyboard. For example, saving a file is something you do a lot. You can use the mouse to click the File menu on the menu bar, and then click Save. But that’s a lot of work just to save the file. Having a toolbar with a Save icon isn’t much better. Since the goal of this book is to save you work, we’ll mostly be looking at using the keyboard, especially for things you need to do a lot. For that reason, we won’t talk much about toolbars. As well as toolbars, SlickEdit also has tool windows. Tool windows tend to contain considerably more information and functionality than toolbars. They are like miniature applications within the editor. There are many tool windows, and it is not feasible to show them all on the screen at the same time. In Figure 1-1, there are several tool windows that are hidden and are only visible through their tabs, which are arranged down the left- and right-hand sides, and across the bottom (under the File Tabs toolbar). In Chapter 3, we will see how to arrange the tool windows effectively and how to invoke them using the keyboard. The most commonly used tool windows can be used quite effectively without the mouse. At the bottom of the screen, on the left, is the message area, which doubles as the command line. We’ll discuss commands and the command line in detail shortly.
8
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 9
Chapter 1: Introducing SlickEdit To the right of the message area are several status indicators. For example, you can see the current line and column, the state of the current selection, and the character code at the cursor position. There is a lot more to SlickEdit than this main window. We cover many dialogs and tool windows throughout the book.
The Build Tool Window One tool window worth mentioning now is the Build tool window. This tool window contains build output when you compile and/or run programs within SlickEdit. We cover compiling and running in Chapter 4. The Build tool window also provides an operating system shell environment. For example, Figure 1-2 shows the Build tool window with the output of a dir command on Windows. You can enter any operating system command in the Build tool window. You can also navigate around the window, scroll back through its history, and copy/paste from and to it.
Figure 1-2
Commands and the Command Line Commands are at the core of SlickEdit’s power and flexibility. Virtually every operation in SlickEdit is a command. For example, simple cursor movement is performed by the commands cursor-up, cursordown, cursor-left, and cursor-right. Complex operations are also performed by commands, such as config and project-compile. In fact, SlickEdit ships with several thousand commands! Don’t worry though; you only need to remember a small fraction of these to master SlickEdit. When a command consists of two or more words, it is defined internally in SlickEdit with the words separated by underscores, like cursor_up. You will use this form when you define your own commands. However, for better readability, SlickEdit displays these commands using hyphens instead of underscores, and they can usually be entered either way: cursor-up or cursor_up. Commands are fundamental to the way SlickEdit works, particularly when customizing and extending SlickEdit via macro programming. For example, when doing macro programming, you probably will have occasion to use the cursor-up command to move the cursor. With this in mind, we focus on command names first and give keyboard shortcuts and menu choices when applicable. When we introduce a feature, we’ll show the SlickEdit command for that feature, and then, if there is one, the standard key binding or menu item.
9
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 10
Part I: Getting Started with SlickEdit Commands can be invoked in several different ways: ❑
All commands can be entered on the command line.
❑
Commands without mandatory arguments can be bound to keyboard shortcuts.
❑
Commands without mandatory arguments can also be added to toolbars and menus.
❑
Commands can be invoked by other Slick-C macros and commands.
Commands can have arguments, and these arguments can be mandatory or optional. For example, cursor-up can take an optional numeric parameter specifying how many lines to move up. When you invoke a command via a keyboard shortcut, toolbar, or menu, no arguments are provided. A command may prompt for an argument in these cases. An example of a command for which you would normally provide an argument is find.
The Command Line The bottom-left area of the SlickEdit window doubles as both a message area and the command line. Use the Escape key to toggle the cursor between the edit buffer and the command line. Even toggling from and to the command line is done by a command: cmdline-toggle. The cmdlinetoggle command is bound to the Escape key in CUA and several other emulations. In other emulations, it is bound to different keys. When you start typing a command, SlickEdit begins prompting with matching commands based on what you have typed, as shown in Figure 1-3.
Figure 1-3
When you enter a command on the command line, you can specify arguments. Many commands know what kinds of arguments they require, and SlickEdit can autocomplete arguments for these commands. For example, if a command requires a filename, SlickEdit can complete filenames or directories from the current directory on the command line. Figure 1-4 shows an example.
Figure 1-4
Autocompletion for command-line arguments works for several other kinds of arguments, as well as files.
10
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 11
Chapter 1: Introducing SlickEdit We’ll show how you can make autocompletion work with your own commands in Chapter 16. When autocomplete for command-line arguments is active, you can also press the question mark key to open a selection list for matching arguments. The command line also supports history. You can navigate backward and forward through the history list using the up and down arrow keys. You can edit commands and execute them again. You can enter several different types of commands on the command line. These include: ❑
SlickEdit Commands — These can be commands provided by SlickEdit, such as find, or commands you write yourself in Slick-C. There is no difference between SlickEdit-provided commands and user-written commands.
❑
Slick-C “batch macros” — These are routines written in Slick-C that are not compiled into internal commands.
❑
Operating System Commands — You can enter any operating system command on the SlickEdit command line, as well as in the Build tool window.
We cover Slick-C batch macros in Chapter 16. If you want to enter an operating system command that has the same name as a SlickEdit command, use the dos command. For example, suppose you want to run the operating system find command. Since there is a SlickEdit command named find, you need to enter dos find on the command line. Although the dos command appears to be named after the DOS operating system, it actually works on all operating systems. An operating system command is run in its own window. The window closes after the command completes. You can use the dos command with the –w option to keep the window open until you press a key. Alternatively, if a command has output you want to see, you can use the Build tool window instead of the command line. There are several SlickEdit commands with the same name as operating system commands. We’ve seen find as one example. A few more are: ❑
cd
❑
del
❑
dir and ls
❑
pwd
Key Bindings You can bind commands to keys. Many commands are bound to keys already when you install SlickEdit. The set of default key bindings you select when you install SlickEdit is called an emulation. In this book, we assume that you are using the CUA emulation. We cover emulations in more detail in Chapter 2.
11
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 12
Part I: Getting Started with SlickEdit If you want to find out what command is bound to a key, use the what-is command, like this:
1. 2.
Enter what-is on the command line, and press Enter. SlickEdit prompts you to press a key. Press a key. If the key has a command bound to it, SlickEdit tells you what command the key runs. Otherwise, SlickEdit pops up a message box saying that the key is not defined.
If you want to find which key(s) a command is bound to, use the where-is command. For example, to find out which key the save command is bound to, enter the command where-is save. SlickEdit displays a message showing the key for the save command.
Setting Key Bindings You can review and edit key bindings using the Key Bindings dialog (Tools ➪ Options ➪ Key Bindings). The Key Bindings dialog is shown in Figure 1-5.
Figure 1-5
The Key Bindings dialog has several different features. Let’s use it to bind a command to a key. The quick-search command is a useful shortcut for searching for the word at the current cursor position. But the command is not bound to a key in the CUA emulation. Let’s bind it to Ctrl+F3 using the Key Bindings dialog. With the dialog open, follow these steps:
12
1.
Enter quick-search in the “Search by command” field. SlickEdit updates the commands listed as you type. When you’ve typed the whole command, the list is narrowed down to just that command. This list also shows that the command is not currently bound to any key.
2.
Click in the “Search by key sequence” field.
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 13
Chapter 1: Introducing SlickEdit 3.
Press Ctrl+F3. If the key is already used by a command, that command is added to the list so that you can see it.
4.
Click the Add button to add the binding. SlickEdit displays the Bind Key dialog, shown in Figure 1-6.
Figure 1-6
5.
Click Bind to bind the key. If the key you have chosen is currently bound to a command, SlickEdit warns you and asks you to confirm that you wish to continue.
A given command can be bound to many different keys, but a given key or key combination can have only one command bound to it. You can use Ctrl, Alt, and Shift combinations to make key bindings unique. For example, Ctrl+Shift+F3 is distinct from Ctrl+F3. Ctrl+Alt+Shift+F3 is different again. Commands can be bound to sequences of keys. For example, you could bind a command to Alt+T followed by P. The beginning part of the sequence cannot itself have a command bound to it, because that would be ambiguous. But you can use different keys for the ending part. You could have one command bound to Alt+T followed by P, and another to Alt+T followed by F. This is one way to overcome the problem of running out of keys, if you want to bind a lot of commands. We’ll see a couple of applications of this idea below. You can use the Key Bindings dialog to review related commands and their key bindings. If you type search into the “Search by command” field, you see all commands containing the word search. The Key Bindings dialog has several other features too. You can remove key bindings, and you can export your key bindings as an HTML file. Most key bindings are done for the default mode, called the fundamental mode in SlickEdit. SlickEdit also has several other modes. Each family of programming languages has a mode, for example, C, Java, HTML. There are also specialized modes for certain SlickEdit features. Some keys have special commands bound to them per mode. For example, some keys trigger syntax assistance for certain programming languages, such as Space, (, and { in C. The Key Bindings dialog shows modes for key bindings, if they apply. Bindings with modes showing as “default” apply to the fundamental mode.
Listing Key Bindings To list all the key bindings, enter the command list-keydefs. SlickEdit creates a new buffer called keydefs.e and fills it with Slick-C definitions for all the key bindings. This listing can be useful for
13
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 14
Part I: Getting Started with SlickEdit comparing large sets of key bindings, such as those provided by different emulations. It can also help sometimes if you are trying to plan a set of key bindings and need to review which keys are currently in use and which are not. Appendix A contains several tables listing key bindings.
Macros The term macro is used generically in SlickEdit to mean any of these things: ❑
Any Slick-C routine.
❑
A Slick-C command.
❑
A Slick-C batch macro.
In this section, we are referring to macros in the command sense. This section shows you how to create your own commands in SlickEdit. We’ll start with recorded macros and then give an introduction to writing macros in Slick-C and compiling them. After reading this section, you will be ready to compile and load the example macros presented throughout the book. We cover macro programming in more detail in Chapter 16.
Recording a Macro The first kind of macro that most people encounter is the recorded macro. This is probably the quickest way to get started with Slick-C programming and is also a great way to see how easy it is. SlickEdit provides two commands for creating recorded macros and playing them back, shown in Table 1-1.
Table 1-1 Command
Key
Description
record-macro-toggle
Ctrl+F11
Start recording macro, or stop recording and save macro.
record-macro-end-execute
Ctrl+F12
Stop macro recording and execute macro.
Let’s record a macro to duplicate the current line. We’ll also bind this key to Alt+quote. It turns out that SlickEdit already has a duplicate-line command. Also, we cover line selections and copy commands in more detail in Chapter 8. For now, just follow along with the example. This example assumes that you have the CUA emulation loaded. Before you start, you also need to have a buffer open with the cursor on a line in the buffer. To record the macro, follow these steps: 1.
14
Invoke record-macro-toggle (Ctrl+F11). SlickEdit prompts you with a message and shows the macro recording status indicator as shown in Figure 1-7.
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 15
Chapter 1: Introducing SlickEdit
Figure 1-7
2. 3. 4. 5.
Invoke select-line (Ctrl+L). SlickEdit selects the line. Invoke copy-to-clipboard (Ctrl+C). Invoke paste (Ctrl+V). SlickEdit pastes a copy of the line. Invoke record-macro-toggle. SlickEdit displays the Save Macro dialog, shown in Figure 1-8.
Figure 1-8
6.
Enter wrox-dup-line as the Macro Name. This becomes the name of the command, if you should want to invoke it from the command line or from another macro.
7.
Click Save. SlickEdit displays the List Macros dialog, shown in Figure 1-9. The List Macros dialog lists user-recorded macros and allows you to manage them.
Figure 1-9
8.
Click Bind to Key. SlickEdit displays the Key Bindings dialog, with wrox-dup-line shown in the command list.
15
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 16
Part I: Getting Started with SlickEdit 9. 10. 11. 12. 13.
Click in the “Search by key sequence” field. Press Alt+quote. Click Add. SlickEdit displays the Bind Key dialog with wrox-dup-line as the command, and Alt+’ as the key sequence. Click Bind. SlickEdit adds the binding and updates the Key Bindings dialog. Click Close to close the Key Bindings dialog.
Congratulations! You have created a macro and bound it to a key. Try it now by pressing Alt+quote a few times. It should duplicate the line the cursor is on. The exact behavior of commands like copy-to-clipboard and paste can vary with some configuration settings. If you are not using CUA emulation, or you have altered other settings, you may need to follow a slightly different sequence of steps to duplicate a line. In particular, if the line remains selected after you invoke copy-to-clipboard, you need to invoke deselect (Ctrl+U) afterward. When you record a macro and save it with a name, SlickEdit places the source code for your macro into a file called vusrmacs.e in your configuration directory. On Windows, the default location for the configuration directory is in the My SlickEdit Config directory in My Documents. The configuration directory is named after the SlickEdit version number, for example, 12.0.2. We cover the configuration directory in more detail in Chapter 2, including how you can specify its name and location. If you record a macro and do not give it a name (e.g., by pressing Escape in the Save Macro dialog), SlickEdit names it last_recorded_macro and stores the source in lastmac.e in your configuration directory. Unnamed macros are handy for sequences of commands you want to repeat quickly a few times, but not save. You can invoke the last unnamed recorded macro using record-macro-end-execute (Ctrl+F12). If you can plan to finish recording your macro so that your cursor is already set up for the first invocation, you can use record-macro-end-execute to finish the recording and execute the macro immediately. This is very handy for doing repetitive edits on multiple lines, or at multiple search matches. We cover some more examples of unnamed macro recording and playback in Chapter 10. If you are recording a macro and wish to abort recording, press Escape. SlickEdit confirms that you have canceled recording with a message, shown in Figure 1-10.
Figure 1-10
Writing a Macro Locate and open the vusrmacs.e file. You should find that it contains content like this: #include “slick.sh” _command wrox_dup_line() name_info(‘,’VSARG2_MACRO|VSARG2_MARK|VSARG2_REQUIRES_MDI_EDITORCTL) {
The macro you’ve recorded for duplicating a line is a nice start, but it could be somewhat better. Some of the drawbacks of the macro as it stands are: ❑
It uses selections, which means it disrupts any existing selection.
❑
It uses the clipboard.
It would be better if we had a command for duplicating a line without disrupting either the selection or the clipboard. We can do this by editing the code SlickEdit placed in vusrmacs.e. Don’t worry too much about the details for now. Change the macro body of wrox_dup_line() to look like this: #include “slick.sh” _command wrox_dup_line() name_info(‘,’VSARG2_MACRO|VSARG2_MARK|VSARG2_REQUIRES_MDI_EDITORCTL) { push_bookmark(); _str the_line; get_line(the_line); insert_line(the_line); pop_bookmark(); }
Now, instead of using clipboard and selection commands, we are manipulating the buffer directly. We also added push_bookmark() and pop_bookmark() to ensure the cursor remains on the original line after duplicating it. We cover bookmarks in more detail in Chapters 5 and 6. However, simply changing the text in the source file is not enough to change the behavior of the macro in SlickEdit. SlickEdit macros are loaded (compiled), thus we need to get SlickEdit to reload our macro. (Recorded macros are automatically loaded.)
Loading a Macro Compiling a macro and loading it into memory in SlickEdit is referred to as loading the macro. To load the macro, ensure that vusrmacs.e is in the current buffer. Then invoke the load command (F12). If there are no errors, SlickEdit reports that the module is loaded, as shown in Figure 1-11.
Figure 1-11
You can place macro code in any file you like. By convention, Slick-C code is stored in files with the extension .e. Throughout this book, we give more examples of Slick-C code. The examples are all included on the accompanying CD-ROM, in files under directories corresponding to the chapter in
17
22150c01.qxd:WroxPro
9/25/07
12:20 AM
Page 18
Part I: Getting Started with SlickEdit which the code is presented. For example, the wrox-dup-line command above is found in Author/ Chapter01/wrox_dup_line.e. To load any example, simply open the .e file in SlickEdit, and invoke the load command (F12). We cover modules and loading in more detail in Chapter 16, along with other aspects of Slick-C programming.
Supplied Macro Source The entire source code for all of SlickEdit’s features that are implemented in Slick-C is included with the product. The macro source is installed in the macros/ directory underneath the product installation directory. In this book, we occasionally refer to files in the supplied macro source.
Summar y In this chapter, we introduced SlickEdit and explained what differentiates it from IDEs and other tools for programming. The most important things that differentiate SlickEdit are: ❑
SlickEdit is configurable.
❑
SlickEdit is extensible.
❑
SlickEdit is programmable.
We covered some central concepts in SlickEdit: the command line, key bindings, and recording and loading macros. These concepts are used throughout the rest of this book. In the next chapter, we look in detail at some general aspects of SlickEdit configuration.
18
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 19
Configuration SlickEdit has hundreds of configuration options. It is one of the most configurable software products you will ever find. As with most configurable software, SlickEdit comes with reasonable defaults. Nevertheless, in this book, we suggest that you should consider some alternatives to the defaults. In some cases, the default settings are designed to make SlickEdit familiar to users with experience with other common programs, such as Visual Studio or Windows Notepad. But Notepad is not the most effective programming editor, and SlickEdit has alternative ways of doing things that can be more powerful. We introduce a few of these in this chapter. In the first part of this chapter, we cover some general information about configuration to give you the big picture. We discuss SlickEdit’s emulations, which provide behavior compatible with a selection of other editors. We introduce the “WROX Emulation,” which extends SlickEdit’s default emulation to provide more key bindings for useful commands. In the second part of the chapter, we take a look at several common settings you might consider changing in order to get the most out of SlickEdit. These include obvious things such as fonts and also some subtler points like how SlickEdit treats cursor movement and line wrapping. Finally, we explain SlickEdit’s configuration directory, and how you can manage SlickEdit configuration data.
Emulations and Key Bindings During the installation process, you are prompted to select an emulation. The emulation defines keyboard shortcuts and other behavior in the editor. SlickEdit ships with more than a dozen emulations, providing compatibility with several other popular editors. Appendix A includes listings of key bindings for some popular emulations. The default emulation is CUA (Common User Access). Some of the other emulations, such as Visual C++ and Visual Studio, are very similar to CUA. Others are different, reflecting quite different user-interface styles.
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 20
Part I: Getting Started with SlickEdit CUA is an acronym for Common User Access, the user interface standard developed by IBM and Microsoft during the 1980s. CUA defines standard menus such as the File and Help menus. It also defines standard behavior for some function keys, such as F1 for help, and key combinations such as Ctrl+X, Ctrl+C, and Ctrl+V for cut, copy, and paste, respectively. You can change emulation at any time by choosing Tools ➪ Options ➪ Emulation from the main menu. You should be aware that changing emulations is not a perfectly reversible process. If you change from CUA emulation to Brief, for example, and then back to CUA, your CUA settings are not completely restored to what they were before. To get a clean configuration with a given emulation, you need to start with a default, or empty, configuration. We cover managing configurations in more detail below in this chapter. Configuring your settings programmatically is also a good way to reset your settings reliably. We cover programmatic configuration in Chapter 17. You can understand key bindings for emulations by reading the emulation chart or using the Key Bindings dialog. To understand emulation settings other than key bindings in detail, you need to study the Slick-C code defining the emulation. The Slick-C files defining the different emulations are listed in Table 2-1.
Table 2-1
20
Emulation
Source File
BBEdit (Mac)
bbeditdef.e
Brief
briefdef.e
CodeWarrior
codewarriordef.e
CodeWright
codewrightdef.e
Epsilon
emacsdef.e
GNU Emacs
gnudef.e
ISPF
ispfdef.e
SlickEdit
slickdef.e
Visual C++ 6
vcppdef.e
Vim
videf.e
Visual Studio
vsnetdef.e
CUA
windefs.e
Xcode
xcodedef.e
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 21
Chapter 2: Configuration
The ‘WROX’ Emulation This book provides an extension to the CUA emulation called the “WROX” emulation. You can find the definitions for the WROX emulation in the file Chapter02/wrox_emulation.e on the book’s CD-ROM. To load the emulation, open wrox_emulation.e in SlickEdit, and invoke the load command (F12). The WROX emulation affects only key bindings. In most cases, it defines additional key bindings for commands not bound in the CUA emulation. In a few cases, it changes CUA key bindings. Many of the bindings in the WROX emulation are copied from the SlickEdit emulation, where the SlickEdit defines a key binding for a key not bound in the CUA emulation. Throughout this book, we assume that you are working with either the CUA or the WROX emulation. When we present key bindings, we identify WROX-specific bindings explicitly; otherwise, all key bindings in this book are defined in the CUA emulation. You can use the WROX emulation as a starting point for your own customizations. As well as adding or changing bindings for commands you use frequently, you can also remove bindings for commands you don’t use, so that you don’t invoke them accidentally.
Alt Keys One standard defined by CUA is that you can use Alt key combinations to access the main menu. Thus, for example, you can press Alt+F to open the File dropdown menu from the main menu bar. This is a convenient and intuitive way to learn the menus in an unfamiliar program. This discussion of Alt keys applies to PC-type keyboards, generally for Windows, Linux, and often for UNIX too. Because Macs use a different keyboard, much of this discussion does not apply to them. Also, the WROX emulation would need to be modified for its Alt key bindings to work on a Mac. Many programs use Alt keys for other functions besides invoking menus. Some programs split the use of Alt keys: The ones that are required for invoking main menu items such as File and Help are reserved for those, and the others are free to be mapped to other functions in the program. SlickEdit provides an option to get more use out of the Alt keys. This option is based on the premise that the menus are mainly used when learning the program, or for functions that are used infrequently. For often-used functions, direct invocation by a keyboard shortcut is faster than using the menu. (It’s less keystrokes, and less screen activity.) If you bind an Alt key that is used as a menu shortcut to a command in SlickEdit, the command takes precedence. For example, Alt+F is the shortcut for the File menu in the menu bar, but the WROX emulation binds Alt+F to fill-selection. When you press Alt+F, you get fill-selection. You might be wondering how you access menu functions with the keyboard with this setting. You press and release the Alt key by itself to invoke the main menu. (This works on most Windows programs as an alternative way to invoke the main menu.) Then you press the mnemonic key for the menu item you wish to invoke, for example, F for the File menu. If you change your mind while the focus is in the menu bar and do not wish to invoke a menu item, press the Escape key to return the focus to the buffer. It should be noted that the “Alt menu” setting on the General tab of the General Options dialog (Tools ➪ Options ➪ General) controls this behavior. If you unselect “Alt menu”, you cannot use the Alt key to toggle the focus to and from the menu bar.
21
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 22
Part I: Getting Started with SlickEdit
Macro Variables Macro variables control a large number of SlickEdit’s configuration settings. Many settings can be changed through the configuration dialogs, but some settings can be changed only by setting the values of macro variables. For example, the def_undo_with_cursor macro variable controls whether undo steps backward through cursor movement. The setting can only be changed through the macro variable. See Chapter 8 for more details about undo in SlickEdit. It is important to understand macro variables for several reasons: ❑
Some settings have no GUI dialog to configure them and can be controlled only by setting macro variables.
❑
Macro variables provide a way to configure SlickEdit programmatically.
❑
Understanding macro variables can help you understand the behavior of many features of the editor, when viewing macro source code.
See Chapter 17 for more details about programmatic configuration using macro variables, and understanding editor behavior. In many parts of this book, when we discuss features, we mention macro variables that are used to configure options on those features. The following sections explain how to query the current value of a macro variable, and how to set a macro variable.
Using the Set Variable Dialog The Set Variable dialog provides a GUI dialog you can use to query or change the value of any macro variable. To query or set a macro variable using the Set Variable dialog, follow these steps:
1.
Invoke gui-set-var (Macro ➪ Set Macro Variable). The Set Variable dialog appears, shown in Figure 2-1.
Figure 2-1
2.
Specify the name of the variable. As you type, a dropdown appears with matching names, as shown in Figure 2-2.
Figure 2-2
22
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 23
Chapter 2: Configuration 3.
When you have selected the desired variable, press Enter. The dialog displays the current value, as shown in Figure 2-3.
Figure 2-3
4.
If you wish to change the value, enter the new value and click OK. SlickEdit updates the variable.
Using the set-var Command While the Set Variable dialog is easy to use, it’s often faster to use the set-var command on the command line. To query or set a macro variable using the set-var command, follow these steps:
1. 2.
Open the command line. Type the command set-var, followed by a space. The command line appears, as shown in Figure 2-4.
Figure 2-4
3.
Type part of the name of the variable. The command line prompts you for matching variables, as shown in Figure 2-5.
Figure 2-5
4.
When you have selected the desired variable, press Enter. The command line displays the current value, as shown in Figure 2-6.
Figure 2-6
5.
If you wish to change the value, enter the new value and press Enter. SlickEdit updates the variable.
23
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 24
Part I: Getting Started with SlickEdit
Common Settings In this section, we cover various common configuration settings. There are many more settings available in SlickEdit other than those covered here. The ones covered here are chosen because they are commonly needed by users but are not necessarily obvious in the interface.
Appearance In this section, we’ll mention a few basic things you can do with the appearance of SlickEdit that might not be obvious. Most of these settings have value beyond pure aesthetics. They are intended to provide visual clues to make you more productive.
Maximize First Window By default when you install SlickEdit, windows are cascaded in the editor. They are small and don’t show many lines of your source files. Check the “Maximize first window” checkbox on the General tab of the General Options dialog (Tools ➪ Options ➪ General). With this setting, buffers are opened in windows that fill the entire SlickEdit application window. This is usually a more effective way of working when programming. We talk about managing windows in more detail in Chapter 3.
Draw Box around Current Line It can be quite helpful to be able to see at a glance which line your cursor is on. SlickEdit provides several choices for this, found on the General tab of the General Options Dialog (Tools ➪ Options ➪ General). You can have no box (the default), a simple box, or one of several ruler styles. Try the ruler styles, and use one of them if you like it; otherwise use the plain box. You can also customize the color of the box or ruler if you wish. You can add per-extension current line highlighting too. This is hidden away in the Advanced tab of the Extension Options dialog (Tools ➪ Options ➪ Extension Options). There are two checkboxes in the Color coding section labeled “Modified lines” and “Current line.” If you check the Current line checkbox, the current line gets color syntax highlighting, in addition to any box or tabs. If you check the Modified lines checkbox, SlickEdit marks changed lines with color in the left margin. The modification markers remain visible as long as the file is loaded. Note that the Current line and Modified lines settings need to be set independently for each file extension. See Chapter 13 to find out other ways you can see what changes you have made to a file.
Vertical Line Column Also on the General tab of the General Options dialog is the option to place a vertical line on the screen at a certain column. You can use this if you prefer to limit the length of lines in your source files, perhaps for printing purposes. Some coding conventions place a maximum on source file line length. You can change the color of the line and what column it appears in.
24
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 25
Chapter 2: Configuration Show Top of File Line Also on the General tab of the General Options dialog is the “Top of file line” option. This line provides a visual cue to show you are at the top of the file. More importantly, depending on your emulation and other configuration settings, some operations that affect the line after the cursor position are not possible unless you can place the cursor before the first line. For example, in the default configuration, copying or moving an entire line places the line after the current line. If you want to copy or move a line to the start of the file, you need to be able to put the cursor before the first line. The top of file line lets you do this. We look at copying and moving lines in Chapter 8.
Left Margin Size SlickEdit places several markers in the left margin, for example, the modified line colors seen above. Another example is bookmark icons. Sometimes when you activate different features in the editor that use the left margin for visual cues, it causes the margin to be resized. This can be distracting. You can reduce the amount of resizing that occurs by setting the margin to a sufficiently large initial size, such as 0.25 inches. This setting is found on the More tab of the General Options dialog. We cover bookmarks in detail in Chapters 5 and 6.
Special Characters Another useful setting for visual cues is to make special characters visible. You can do this by invoking view-specialchars-toggle (View ➪ Special Characters). Special characters include: ❑
End of line.
❑
Tab.
❑
Space.
❑
Virtual Space.
❑
End of File.
You can customize how SlickEdit displays each special character on the Special Characters tab of the General Options configuration dialog.
Fonts Fonts are a rather obvious visual setting. SlickEdit allows you to change the font for several different screen elements. Use the Font Configuration dialog (Tools ➪ Options ➪ Fonts) to configure fonts. The most important elements are: ❑
SBCS/DBCS Source Windows (Single-Byte Character Set and Double-Byte Character Set) — Used for most programming work.
❑
Hex Source Windows — Used mostly for displaying binary files and checking for special characters.
❑
Unicode Source Windows — Used mostly for XML.
We discuss some Unicode-specific issues in more detail in Chapter 12.
25
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 26
Part I: Getting Started with SlickEdit However, if you change these, you will likely also want to change: ❑
File Manager Windows.
❑
Diff Editor Source Windows.
❑
Selection List.
You need to change the font for each screen element individually. Chapter 17 shows how you can use a Slick-C script to set your fonts programmatically. There are many resources on the Web for fonts for programming. You can find a lot of fonts listed and compared at these sites: ❑
http://keithdevens.com/wiki/ProgrammerFonts
❑
http://www.lowing.org/fonts/
The default font for SlickEdit on Windows is Courier New. While this is a widely used monospaced font, it is not specifically designed for programming. Some people find the serif look of Courier New cluttered and distracting and prefer a more open sans-serif font. Lucida Console is also available as standard with Windows and is less cluttered than Courier New. However, the spacing and relative sizes of characters are still not ideal for programming. Bitstream Vera (http://www.gnome.org/fonts/) is an example of a font that works well for programming. It is open and clear. It has a numeric 0 (zero) that is easily distinguished from a capital O (“oh”), and a numeric 1 (one) that is easily distinguished from a lowercase L. It also has large, easily distinguished punctuation characters such as colon, semicolon, period, and comma. SlickEdit ships BitStream Vera in its Mac installation. For other operating systems, you can download BitStream Vera from the URL above. Try it out.
Line Behavior One fundamental choice you can make when using SlickEdit is whether you want the editor to treat the buffer as a stream of text, or a collection of lines. Most Windows and UNIX editors lean toward the stream model for text. Thus, for example, if you move the cursor to the end of a line, and then try to move to the right, the cursor comes to the beginning of the next line. This is nice for word processors, but is usually not appropriate for programming. When programming, you are typically working with lines. For most programming languages, a line represents a statement. The next line is the next statement. When you press the right arrow key, you want the cursor to move to the right, even if it is currently at the end of the line. You may be trying to add a line comment, for example. In the CUA emulation, SlickEdit follows the stream model, as that is the most familiar to many users. Some emulations, such as the SlickEdit emulation, use the line model instead. Alternatively, you can control the line behavior using several related configuration settings. Rather than having a single line behavior setting, SlickEdit allows you to change several related behaviors independently. All of the line behavior settings are found in the Redefine Common Keys dialog (Tools ➪ Options ➪ Redefine Common Keys), shown in Figure 2-7.
26
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 27
Chapter 2: Configuration
Figure 2-7
Line Wrapping and White Space The checkboxes in the lower part of the Redefine Common Keys dialog are mainly concerned with white spaces and tabs. Note that these checkbox settings actually have nothing to do with the common key settings in the upper part of the dialog. Table 2-2 contains descriptions of the checkbox settings, and more notes follow afterward.
Table 2-2 Setting
Description
Cursor wrap
When on, the cursor-left and cursor-right commands wrap when the cursor is at the beginning or end of a line. When off, the cursor commands can take the cursor beyond the end of the line.
Up/Down on text
When on, the cursor stays within the text when moving up and down. When off, the cursor remains in the same column, whether or not the text extends to that column.
Up/Down within soft wrapped lines
When on, the cursor moves up and down window lines in soft wrapping mode. When off, the cursor moves up and down buffer lines. See note below.
Line wrap on text
When on, the cursor can move to column 1 regardless of margins in word wrap mode. When off, the cursor wraps at the left margin in word wrap mode. See note below.
Jump over tab characters
When on, the cursor jumps over tab characters in the buffer. When off, the cursor can be moved “into” tab characters, one space at a time. Typing inside a tab character converts the tab to the appropriate number of spaces. continued
27
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 28
Part I: Getting Started with SlickEdit Table 2-2 (continued) Setting
Description
Pull chars backspace
When on, in both insert and replace mode, backspace pulls characters to the right of the cursor with the cursor while deleting. When off, in replace mode, characters are not pulled. Spaces are left instead.
Hack tabs backspace
When on, backspace converts tabs to spaces and deletes only one space. The cursor moves back only one column. When off, backspace deletes entire tab characters, moving the cursor back to the character before the tab.
Treat leading spaces as tabs
When on, the cursor moves by tab stops in leading spaces on the line. When off, the cursor moves one column at a time.
The “Up/Down within soft wrapped lines” setting applies only in soft wrapping mode. Soft wrapping mode displays long buffer lines as multiple lines in the window, marking a continuation with a little arrow on the right-hand side. Turn on soft wrap globally or per file extension on the Word Wrap tab of the Extension Options dialog (Tools ➪ Options ➪ File Extension Setup). The “Line wrap on text” setting applies only in word wrap mode. When word wrap mode is on, SlickEdit wraps text you type to stay within the left and right margin columns. Turn on word wrap per file extension on the Word Wrap tab of the Extension Options dialog. A related setting concerning line wrapping is the “Click past end of line” checkbox on the General tab of the General Options dialog. This setting permits a mouse click to place the cursor beyond the end of a line with a mouse click. If you turn off “Up/Down on text,” you would probably also turn on “Click past end of line.” If you type something beyond the end of a line, the space in between becomes padded with spaces. If you delete the text, the trailing spaces remain. You can remove trailing spaces from a line using removetrailing-spaces (Edit ➪ Other ➪ Remove Trailing Whitespace). However, if you turn on “Strip trailing spaces” in the Save tab of the File Options dialog (Tools ➪ Options ➪ File Options), this is not usually necessary.
Backspace, Delete, and Enter The Redefine Common Keys dialog contains five common keys and their standard commands in the top part. This part of the dialog is simply a shortcut for binding a limited set of possible commands to each of these five keys. For the Backspace, Delete, and Enter keys, the choices available determine the line behavior. For example, the default command for Delete (in CUA) is linewrap-delete-char. If you press Delete on the end of a line, the following line is joined to it. If you configure the key to the other option, delete-char, then Delete never joins lines. Backspace is similar, with commands linewrap-rubout and rubout. These commands differ when the cursor is on the beginning of the line.
28
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 29
Chapter 2: Configuration For the Enter key, there are three choices: nosplit-insert-line, split-insert-line, and maybesplit-insert-line. When you change the behavior of Enter using the Redefine Common Keys dialog, SlickEdit also changes Ctrl+Enter to the complementary behavior. The behaviors are shown in Table 2-3.
Table 2-3 Command for Enter
Description
Command for Ctrl-Enter
nosplit-insert-line
Does not split line. A new line is added below the current line.
split-insert-line
split-insert-line
Splits line.
nosplit-insert-line
maybe-split-insert-line
In insert mode, splits line. In replace mode, moves cursor to first column of next line.
nosplit-insert-line
The pair split-insert-line and nosplit-insert-line are both commonly used while programming. Decide which you prefer as your default, and use the other with the Ctrl key. Or use maybe-splitinsert-line if that behavior works for you. All of these commands are integrated with other SlickEdit features. For example, if you are editing a source file with comments, the line splitting and joining in these commands attempt to keep the comment flow intact. Thus if you press Enter to insert a line break in a comment, SlickEdit continues the comment to the next line. If you decide to replace the standard commands with something of your own, you may need to consider whether you will lose some of this functionality. Of course, if you study the Slick-C source for commands such as split-insert-line, you can provide the same functionality in your own commands. Regardless of your settings for common keys for splitting and joining lines, you can also use split-line (WROX: Alt+S) and join-line (WROX: Alt+J) as alternatives. These commands provide more rudimentary splitting and joining, however. They don’t preserve comment flow.
Home and End The Home and End keys also have two behaviors each that can be selected in the Redefine Common Keys dialog. For Home, the choices are begin-line and begin-line-text-toggle. The begin-line command simply takes you to the beginning of the line, regardless of any indentation. The begin-linetext-toggle command toggles you between the first non-blank character and the beginning of the line. This can be handy for heavily indented lines. Similarly, the End key can have either end-line or end-line-text-toggle. The end-line command takes you to the end of the line, including any white space. The end-line-text-toggle command toggles between the last non-blank character and the end of the line. Again, this command would be useful if you had a lot of lines with trailing white space. This isn’t as common as having indented lines.
29
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 30
Part I: Getting Started with SlickEdit
Managing Configurations When you install SlickEdit, files are placed in two directories: ❑
The program installation directory.
❑
The user configuration directory.
The program installation directory contains the static files that don’t change once they are installed. These include executable files, libraries, help system, templates, and macro source code. The default location for the program installation directory on Windows is C:\Program Files\SlickEdit 2007\. On UNIX, it is a global directory such as /opt/slickedit/. The user configuration directory contains all configuration data and other user data. The configuration data are initialized to defaults, and then may change as you use SlickEdit. We cover the content and management of the configuration directory in this section.
Configuration Directory SlickEdit stores all your personal configuration data in the user configuration directory. By default, this directory is located under your home directory. SlickEdit creates a separate configuration directory for each update release. Thus for SlickEdit 12.0.2 on Windows, the default location for the user configuration directory is My Documents\My SlickEdit Config\12.0.2. On UNIX, the configuration directories are placed under $HOME/.slickedit/. If SlickEdit cannot find the default configuration directory when it starts, it tries to find a configuration directory for a previous version. If it finds one, SlickEdit migrates the configuration settings from the previous version to the current version. The configuration directory contains several files. The most important file is the SlickEdit state file, stored in vslick.sta on Windows and vslick.stu on UNIX. This is a binary state file that contains many of SlickEdit’s configuration data. It includes most of the user settings and all compiled macro code. An important thing to realize about the state file is that it is normally only saved when you exit from SlickEdit. This means that if you change your configuration, and then the editor gets terminated abnormally (e.g., because of a power outage), your changes are not saved. You can force SlickEdit to save the state file during a session using the save-config command. If you have made configuration changes that you do not wish to save, you can discard them by exiting SlickEdit using the safe-exit command. There are several other configuration files and subdirectories too. Some of these are listed in Table 2-4.
Reverting to the Default Configuration Sometimes you may wish to revert SlickEdit to the default configuration. To do this, delete the contents of your configuration directory before starting SlickEdit. If SlickEdit finds an empty configuration directory, it initializes it with the default configuration.
Slick-C representation of key bindings, user settings (see Chapter 17).
vusrobjs.e
Toolbar customizations.
There are several other files in the configuration directory. Refer to the online Help for a more complete table. If you delete the directory itself, instead of just the contents, then SlickEdit will look for configuration directories for previous versions, which is probably not what you want. You can back up your entire SlickEdit configuration by making a copy of the configuration directory. If you encounter a problem with SlickEdit, it could be due to a corrupt configuration. You can try restoring a backup configuration, or reverting to the default configuration. We cover advanced ways to restore your configuration to a known state in Chapter 17.
Working with a Different Configuration Occasionally you may wish to run SlickEdit using a different configuration directory from the default. Some examples of times you might want to do this are: ❑
You want to place your configuration in a different location. For example, your home directory may be on a network drive, and you want to put your SlickEdit configuration on the local drive.
❑
You want to try something with a default configuration.
❑
You want to experiment with different settings.
31
22150c02.qxd:WroxPro
9/25/07
12:22 AM
Page 32
Part I: Getting Started with SlickEdit To use a non-default configuration directory location, you can use one of these options: ❑
Set the environment variable VSLICKCONFIG to point to your configuration directory.
❑
Use the –sc option when invoking SlickEdit to specify the configuration directory.
These options are documented in the online Help. Both of these options override the version migration mechanism described above. If you do override the configuration directory location, be careful to remember that fact. For example, if you need to revert to the default configuration, or you receive instructions from SlickEdit Support, it’s important that you perform the actions in the correct directory. Another way to use different configurations without changing where SlickEdit looks for the configuration directory is to keep different copies of the directory and contents with different names, and rename the one you wish to use to the default name. For example, suppose in your My SlickEdit Config folder you have two backup copies of the 12.0.2 configuration directory: 12.0.2_safe and 12.0.2_ experimental. By copying or renaming one of these to the default name, 12.0.2, you make it the active configuration. To switch to the other, stop SlickEdit, rename the directories as desired, and restart.
Summar y We covered a selection of the most common configuration settings in this chapter. There are many, many other settings. Some of these settings are quite obscure and do not affect most users. You are referred to the reference information in the online Help for those. For example, we don’t discuss network or proxy settings. Other settings are rather obvious and do not need to be covered here. For example, you should not have much trouble figuring out how to change colors if you decide you want to. Many other configuration settings apply to specific topics that are covered elsewhere in this book, and they are covered together with those topics. In the next chapter, we take a look at using and configuring the different windows of the interface.
32
22150c03.qxd:WroxPro
9/25/07
12:23 AM
Page 33
Managing Windows When I started using the ancient ancestor of SlickEdit, the E editor on DOS in the 1980s, screens had only 25 lines and 80 columns. The editor had a command line, a status line, and a help line. I could see 22 lines of my file, and those lines were not particularly long. Figure 3-1 shows this old editor.
Figure 3-1
These days we have GUI environments and much bigger screens. Many programmers now use a monitor at a resolution of 1600 × 1200 or more. With that kind of screen, in full screen mode it’s easy to get 60 or 70 lines on the screen, with a couple of hundred columns. (And, if you don’t mind a 6-point font, you can get a lot more.) This is usually enough space, because most people’s brains can’t cope with more lines of code than that anyway. The thing is, our desktops and tools are a lot more sophisticated now, and they want to give us a lot more information, and give us more different ways of doing things. Some Office-style applications start up with three or four rows of toolbars. IDEs usually have extra windows on the sides and bottom, for different types of navigation. SlickEdit also has a lot of toolbars and tool windows.
22150c03.qxd:WroxPro
9/25/07
12:23 AM
Page 34
Part I: Getting Started with SlickEdit If you use them all, you can easily get back to a situation where you can see only 20 lines or less of your code. The trick is to manage the toolbars, tool windows, and your editing area to maximize your productivity. SlickEdit allows several options for how you arrange its tools. In this chapter, we take a look at those options and recommend some strategies for using the features most effectively.
Windows and Buffers When you look at the SlickEdit interface with the Edit window maximized, it’s easy to think that the editor has a single editing window, into which it places the buffer you are editing. This is not really true. The relationship between windows and buffers is controlled by the “One file per window” setting, found on the General tab of the General Options dialog (Tools ➪ Options ➪ General). The default is “One file per window” turned on, which is usually the best setting. With this setting, there is actually a separate window for each buffer. You can move among buffers effectively using either next-window (Ctrl+Tab) or next-buffer (Ctrl+N). We discuss commands for moving between buffers in more detail in Chapter 6. With the “One file per window” setting turned off, you can associate more than one buffer with a window. With this setting, next-window moves between windows, and next-buffer moves between buffers associated with the window. This is mostly useful when using split windows.
Split Windows In the default configuration, SlickEdit displays windows cascaded. Usually for programming, it’s more effective to maximize the Edit window. You can change the default behavior by checking the “Maximize first window” option on the General tab in the General Options dialog (Tools ➪ Options ➪ General). Often while programming, you need to look at two files at once. Or, you may want to look at two different parts of the same file at once. Table 3-1 shows some commands you can use for working with split windows.
Table 3-1
34
Command
Key
Description
hsplit-window
Ctrl+H (Window ➪ Split Horizontally)
Split window horizontally
vsplit-window
(Window ➪ Split Vertically)
Split window vertically
one-window
(Window ➪ One Window)
Restore to single window
22150c03.qxd:WroxPro
9/25/07
12:23 AM
Page 35
Chapter 3: Managing Windows When using split windows, it’s best to have “One file per window” turned off. Then you can use next-window/prev-window (Ctrl+Tab/Ctrl+Shift+Tab) to move between the windows, and next-buffer/prev-buffer (Ctrl+N/Ctrl+P) to move between buffers in a window.
Full Screen Regardless of your monitor size and resolution, there are times when you want to see as much of your buffer as possible, and nothing else. An example of this is when editing a large, badly formatted HTML file. Another example is when you are working with many columns of data, and splitting the lines is not possible because it would prevent block editing. In these cases, you may find full screen mode handy. Use the fullscreen command (View ➪ Full screen) to toggle full screen mode. When in full screen mode, SlickEdit displays the menu bar, the left margin, the scroll bars (if turned on), and the command line and status area. Nothing else is shown, and you have the maximum amount of your buffer visible.
Toolbars I have a rather harsh view of toolbars. I think they are basically invented for and useful only for marketing purposes. Everybody seems to have one these days, whether useful or not. SlickEdit’s “Standard” toolbar has many frequently used tools. The tools are used so frequently that you will be working very slowly if you use the toolbar to invoke them. These tools include file load and save commands, clipboard and undo commands, and search-and-replace commands. You need to know the keyboard shortcuts for all of these commands to use SlickEdit effectively. There is no reason for most users to use the Standard toolbar. You can save some space by removing it and also the Current Context toolbar. Some of the more specialized toolbars are handy though, especially if they are for features that you don’t use frequently. I don’t use the debugger very often, so when I do use it, I use the toolbar for a lot of its commands. If I used the debugger more often, I would learn the keyboard commands. As a general rule, you should avoid using toolbars when using SlickEdit. Learn and use the keyboard bindings for commands. If you like toolbars regardless, you can adjust the size and other options for the icons on the Options tab of the Toolbar Customization dialog (View ➪ Toolbars ➪ Customize).
Tool Windows Tool windows are different from toolbars. Tool windows provide you with different kinds of information, and different functionality, from that available in the main editing area. Depending on the work you are doing, you will use some tool windows frequently and others not at all.
35
22150c03.qxd:WroxPro
9/25/07
12:23 AM
Page 36
Part I: Getting Started with SlickEdit Even so, for most of the tool windows, you won’t want to have them visible all the time — they simply take up too much room. There are more than a dozen of them, thus it’s impossible to display them all anyway. The best strategy is to arrange the tool windows so that you can access the ones you need quickly, and dismiss them just as quickly. With the default configuration this is not possible, since you need to use the mouse to activate most of the tool windows and also to hide them. Fortunately, tool window features make it pretty easy to set things up to be productive with the keyboard. The WROX emulation supplied with this book contains one approach to managing the tool windows with the keyboard. Before we go into details of the key bindings, let’s take a bit of time to understand some things about tool windows.
Tool Window Arrangement Tool windows can be either floating or docked. Floating tool windows can be placed anywhere on the screen. They do not have to be placed within the SlickEdit window. In fact, it’s often better to place them outside it, so that they do not obstruct the view of the buffer. If you place a floating tool window outside the main SlickEdit window, you can leave it visible all the time if you choose. You can close a floating tool window by clicking the X in its top-right corner. You can also press Escape to close some floating tool windows. For most floating tool windows, though, pressing Escape does not close the window but instead restores the focus to the main SlickEdit window. Docked tool windows are stuck to the inside of one edge of the main SlickEdit window: either the left, top, right, or bottom edge. Docked tool windows belong to docking groups. Only one tool window in a docking group can be visible at a time. The others show only their tabs in the docking group. You can switch among tool windows in a docking group by clicking tabs, but our goal is to switch using the keyboard, not the mouse. Docking groups can have auto-hide enabled for them. If auto-hide is not enabled, the docking group remains visible all the time, taking up a certain amount of screen space. If auto-hide is enabled, the docking group remains visible only while it has the focus or the mouse is over it. When the focus is moved away and the mouse is not over the docking group, it disappears. Auto-hide is indicated by a pin icon on the top right of the docking group, next to the Close icon. If the pin is upright, auto-hide is disabled. If the pin is on its side, auto-hide is enabled. Figure 3-2 shows some arrangements of tool windows. The Find Symbol tool window is floating and appears over everything else. It could be moved outside of the SlickEdit window if desired. The lefthand docked group contains the Projects, Defs, Class, Symbols, and Files tool windows. The group has auto-hide enabled and is, in fact, hidden so that only the tabs are visible. The bottom docked group contains the Search Results, Preview, Build, Output, and References tool windows. The group has auto-hide enabled, as indicated by the pin on its side in the upper-right. The group is visible because the Build tool window, displaying a directory listing, currently has the focus. The right-hand docked group contains the Bookmarks and Backup History tool windows. The group has auto-hide disabled, indicated by the upright pin in the upper-right corner. The Bookmarks tool window is visible. The Backup History tool window is shown only by a tab, which is, in fact, covered by the Build tool window. Auto-hidden tool windows appear over non-auto-hidden tool windows when they are showing. When tool windows are not auto-hidden, SlickEdit arranges them so that they don’t overlap.
36
22150c03.qxd:WroxPro
9/25/07
12:23 AM
Page 37
Chapter 3: Managing Windows
Figure 3-2
You change a tool window to floating or docked mode by right-clicking on its title bar. To change a floating tool to docked, and to add it to a docking group, follow these steps:
1. 2. 3. 4.
Ensure that the docking group has auto-hide turned off and is visible. Right-click on the floating tool window’s title bar. SlickEdit displays its title context menu. If the window is not already dockable, click Dockable to make it dockable. Drag the window to dock it in the desired docking group. Drag the mouse pointer to the title bar of the desired docking group. When the mouse pointer is in the title bar, the docking group pane is selected with a black rectangle. This is shown in Figure 3-3, where a tool window is being docked to a group already containing the Projects tool window.
Figure 3-3
37
22150c03.qxd:WroxPro
9/25/07
12:23 AM
Page 38
Part I: Getting Started with SlickEdit 5. 6.
Drop the tool window. It now joins the docking group. Enable auto-hide on the docking group, if desired.
You can rearrange the order of tabs in a docking group by dragging them. To change a docked tool window to floating, follow these steps:
1. 2. 3. 4. 5. 6.
Ensure that the docking group has auto-hide turned off and is visible.
7.
Drag the tool window to the desired location, and resize it if necessary.
Select the tool window you wish to make floating. Right-click on the tool window’s title bar. SlickEdit displays its title context menu. Click Floating to make the tool window floating. It detaches from the docking group. Right-click on the tool window’s title bar. SlickEdit displays its title context menu again. Click Dockable to make the tool window not dockable. Now, when you drag the window around to position it, SlickEdit will not accidentally dock it.
What’s the best arrangement for tool windows? It depends on you. If you have a large screen and don’t mind SlickEdit putting its tool windows all over it, you may find floating tool windows convenient. They can be shaped more flexibly than docked tool windows. If you prefer to keep all SlickEdit’s tool windows within the main editor window, you will prefer docked tool windows. When docked, some tool windows work better with a horizontal layout, and some work better vertically. For example, the Build tool window works best docked at the bottom of the screen, as in the default configuration. Some tool windows can adapt themselves to either horizontal or vertical orientation. For example, the Find Symbols tool window moves its options panel to the right-hand side of the tool window when it is docked horizontally, and to the bottom if it is in a vertical arrangement. When choosing docking groups for docked tool windows, consider which combinations of tool windows you might like to have visible at the same time. Some tool windows, such as Preview, are constantly updated and can be useful while working with your code. Others are used for specific tasks and are best closed or hidden when not being used.
Activating Tool Windows with the Keyboard Make sure that you have loaded the WROX emulation, described in Chapter 2. The WROX emulation defines keyboard sequences for activating each of the tool windows, listed in Table 3-2. The keyboard sequences all begin with Alt+T, for “tool window,” and are followed by a key that is supposed to be a mnemonic for the specific tool window. Many of the tool windows start with the same letter, thus some of the mnemonics are less natural than others. If you have a preferred set of tool windows you use, you can easily customize the emulation to personalize your mnemonics. Most of the tool windows don’t have standard keyboard bindings in SlickEdit, but some of them can also be reached by other means using the keyboard. For example, activate-files-files is the same as list-buffers, which is bound to Ctrl+Shift+B. Of course, all of them can be reached via View ➪ Toolbars, but that’s a little slow for frequent use, particularly since there are no mnemonics for the tool windows in the cascaded menu.
38
22150c03.qxd:WroxPro
9/25/07
12:23 AM
Page 39
Chapter 3: Managing Windows Table 3-2 Command
Key
Tool Window
activate-bookmarks
Alt+T, K
Bookmarks
activate-build
Alt+T, B
Build
activate-call-stack
Alt+T, A
Slick-C Call Stack
activate-tbclass
Alt+T, C
Class
activate-defs
Alt+T, D
Defs
activate-deltasave
Alt+T, H
Backup History
activate-files-files
Alt+T, L
Files: Open Files tab
activate-files-project
Alt+T, P
Files: Project Files tab
activate-files-workspace
Alt+T, W
Files: Workspace Files tab
activate-find-symbol
Alt+T, F
Find Symbol
activate-ftp
Alt+T, T
FTP
activate-open
Alt+T, O
Open
activate-output
Alt+T, U
Output
activate-preview
Alt+T, V
Preview
activate-projects
Alt+T, J
Projects
activate-references
Alt+T, R
References
activate-regex-evaluator
Alt+T, X
Regular Expression Evaluator
activate-search
Alt+T, S
Search Results
activate-symbols-browser
Alt+T, Y
Symbols
With this configuration in place, you can use the Alt+T keyboard sequence to activate any tool window, then Escape to dismiss it or move the focus back to the buffer. In this way, you can maximize your screen space and access any tool window functionality with a couple of key strokes. An alternative to this scheme is to use keyboard bindings to toggle tool windows, rather than only to activate them. For most of the activate-xyz commands shown in Table 3-2, there are corresponding toggle-xyz commands that toggle the tool windows. You can find all the tool window commands in the supplied Slick-C macro source, in the tbcmds.e file. By consulting that file, you can find out how
39
22150c03.qxd:WroxPro
9/25/07
12:23 AM
Page 40
Part I: Getting Started with SlickEdit the tool windows are managed in detail and possibly design your own scheme for managing and arranging them. If you want to keep a tool window visible for an extended period, while you work on a particular task, you can turn auto-hide off for its group. Turn auto-hide back on afterward to get better screen utilization.
Tool Window Animation Another thing you may or may not like about tool windows in docked mode is the way they slide across the screen when being activated or hidden. You can adjust the rate at which they move, or disable the animation altogether, in the Options tab of the Toolbar Customization dialog (View ➪ Toolbars ➪ Customize). I recommend turning off the animation, since it is distracting and slows things down.
Restoring the Defaults You can restore your toolbars and tool windows to the shipped settings by invoking the tbResetAll command on the command line.
Summar y The SlickEdit user interface is powerful and flexible. Learn which tool windows are useful for your work, and make sure they are quickly available. You can use the keyboard scheme presented in this chapter, or adapt it for your own needs. In the next chapter, we look at workspaces and projects, which enable many of SlickEdit’s advanced code editing features.
40
22150c04.qxd:WroxPro
9/25/07
12:25 AM
Page 41
Part II: Using SlickEdit Chapter 4: Workspaces and Projects Chapter 5: Context Tagging Chapter 6: Navigation Chapter 7: Search and Replace Chapter 8: Editing Text Chapter 9: Editing Code Chapter 10: Editing Data Chapter 11: Aliases and File Templates Chapter 12: Document Types Chapter 13: Comparing and Merging Chapter 14: Version Control
22150c04.qxd:WroxPro
9/25/07
12:25 AM
Page 42
22150c04.qxd:WroxPro
9/25/07
12:25 AM
Page 43
Wor kspaces and Projects With most programming IDEs, you organize your work into projects. In some IDEs, you cannot open a file unless it is part of your project. With SlickEdit, it’s easy to open any file on your system, but all the same it’s usually best to organize your work to get the most effective use of the editor’s features. SlickEdit organizes your work using two concepts: workspaces and projects. Workspaces and projects are important for two main reasons: ❑
They allow you to organize, manage, and tag the files in your project.
❑
They provide structure around tasks such as building, running, and debugging your project.
Tagging refers to SlickEdit’s ability to index the symbols in your code for navigation and smart assistance features. We go into SlickEdit’s tagging features in more detail in Chapter 5. To organize your work using SlickEdit’s workspaces and projects, you create a workspace. In the workspace you add one or more projects. SlickEdit stores the workspace details in a .vpw file, and the project details in one or more .vpj files. SlickEdit also creates a tag file (.vtg) to tag your project files and a .vpwhist file that contains state information about your workspace. A workspace contains a set of projects and retains the state of an editing session. Opening a workspace returns you to the same state you were in when you last worked on this workspace, including the set of open files. Files are added to projects, and projects are added to workspaces, thus you cannot directly add a file to a workspace. You can open files that do not belong to any of the workspace’s projects, and they will be available for editing in the next session if not closed. A project can be just a set of files, but if you are using the SlickEdit build system, then a project corresponds to a build target, something that gets built. For Java, it’s common to have a single
22150c04.qxd:WroxPro
9/25/07
12:26 AM
Page 44
Part II: Using SlickEdit project. For C/C++, you would have a project for each library, DLL or SO, that is built and one for each executable. Even if you don’t use the SlickEdit build system, partitioning files into projects like this is useful so that you can see the structure of your projects and do things like restricting searches to the current project. Projects can be shared between workspaces. Once a project is defined, you can add it to a different workspace. The exact same project is shared; it is not a copy. This is useful if you have internal libraries that might be used and edited in multiple programs. SlickEdit does not require that the files in a workspace be under the workspace directory. They can be located anywhere on the local machine or on a network, although local is always best. Some prefer that structure, creating a single root directory that contains subdirectories for each project, which contains a source tree. However, you can create a workspace directory that has no subdirectory and stores projects and files in other directories. Even if your source files are remote, it is very important to have your workspace and project files stored locally. SlickEdit tags all of the files in a workspace (i.e., all of the files in the projects that the workspace contains) and creates the workspace tag file. It does not have project-specific tag files. For code that is used but not edited, it is generally best not to add it to the project. Instead, tag the library, and add the tag file to your environment. Because of the way in which Context Tagging works, it’s best to restrict your files to those that will be edited. When you create a project, it is critical to get the project type correct. It is impossible to change some project types into others. For example, if you create a Generic C/C++ project, you will never be able to configure it through the GUI to work properly with GNU C/C++. You need to start with that project type to be successful. Projects can be dependent on one another, creating a build dependency. If you have multiple projects, certain operations work on the Active Project. It is shown in bold in the Project tool window. You can change the Active Project by right-clicking on it or using Project ➪ Set Active Project. SlickEdit cannot create Microsoft Visual Studio project types. It can open them and change the set of defined files, but you have to create the solution or project in Visual Studio before opening it in SlickEdit. You will also have to make most of the changes related to build settings in Visual Studio. In this chapter, you will see how to create workspaces and projects. We’ll take a look at how to set up projects for different build targets in your work, and how to automate building and testing your project in SlickEdit. We’ll look at several examples using programming languages with compilers — C/C++ and Java — and also an example of using SlickEdit projects with an interpreted language, Ruby. You can find the code for the sample projects on the accompanying CD-ROM. For compiled languages such as C++ and Java, SlickEdit provides dialogs with a large number of compiler and linker options. Most of the options you can use with the command-line tools are available through the SlickEdit GUI. However, we don’t cover the compiler options in detail here, or even all the compilers. You can find better information about using a compiler in that compiler’s own documentation. Instead, we focus on using SlickEdit with programming language compilers and interpreters in general, and how to create an effective and productive development workflow using SlickEdit.
44
22150c04.qxd:WroxPro
9/25/07
12:26 AM
Page 45
Chapter 4: Workspaces and Projects
How to Organize Your F iles When you create a workspace and a project, SlickEdit creates these files: ❑
project_name.vpw — the workspace definition.
❑
project_name.vpj — the project definition.
❑
project_name.vtg — the tag file.
❑
project_name.vpwhist — the workspace state.
The workspace definition contains a list of projects in the workspace, and other global parameters. The project definition defines all the files in a project, and all the tools and configuration targets for the project. These two files could be checked into version control along with the rest of your project source, if you want to share project definitions and tool configuration with other team members. The tag file contains tags for your projects. The tag file is derived from data in your source files and should not be checked into version control. It should be considered a transient file, like compilation outputs. The workspace state file saves the state so that SlickEdit can restore it when you reopen the workspace. For example, it contains the list of buffers open and the file history. The workspace state file should not be checked into version control, as it is transient and specific to each developer. When you add files to a project, you have three choices: ❑
Add files.
❑
Add tree.
❑
Add wildcard.
Add tree is really just an alternative form of add files. They both result in the same information in the project file: Each file is explicitly listed in the project. Add wildcard is different. It stores the wildcard pattern in the project, rather than the specific files. Each of these approaches has its advantages and disadvantages. Storing each specific file gives more precision and can give better performance. Storing wildcards gives more convenience. Which you choose depends on the nature of your project and what other tools you and your other developers are using. If you are all using SlickEdit, and no other tool to create files in your project, you may find that storing specific files in your project works best. If a team member adds a file and commits his project definition file, other team members will pick up the changes next time they update from the repository. On the other hand, if you often have new files added to the project from outside of SlickEdit, you may find that it is too labor-intensive and error-prone to keep the SlickEdit project file up-to-date with the correct project source files. In this case, you may find that wildcards are better. Generally speaking, wildcards are more convenient than specific files. Once you have them set up correctly, you can pretty much forget about them, and SlickEdit will always be up-to-date with the source files in your project.
45
22150c04.qxd:WroxPro
9/25/07
12:26 AM
Page 46
Part II: Using SlickEdit Some people have experienced performance problems with wildcards with large projects. If you run into performance problems, you should try both methods to see if one is faster.
The Example For our example projects, we’ll create a simple console application that uses only a few files. We’ll see how to: ❑
Organize the source files.
❑
Compile or build the application.
❑
Run automated unit tests, and then review the results.
❑
Run the application itself.
We’ll see how SlickEdit integrates with popular build tools such as Make and Ant. We’ll also see how SlickEdit can interpret output from compilers and tests to help you navigate to errors. Our simple console application solves the n-queens problem. This is a nice programming puzzle where you have to find an arrangement of n queens on an n × n chessboard so that none of the queens attacks any other. The smallest board that it’s possible to do this on is a 4 × 4 board. A 4 × 4 solution is shown in Figure 4-1.
Figure 4-1
To show how to set up SlickEdit projects for different languages and compilers, we’ll work through the example in three different languages: ❑
GNU C/C++.
❑
Java.
❑
Ruby.
The source code for each project is included on the accompanying CD-ROM, under Author/Chapter04/ projects.
46
22150c04.qxd:WroxPro
9/25/07
12:26 AM
Page 47
Chapter 4: Workspaces and Projects
Creating a GNU C/C++ Project To use SlickEdit with a GNU C/C++ project, you need to have the GNU C/C++ compiler and related tools installed already. On GNU/Linux, you should have this installed by default on your development machine. On Windows, the easiest way to install GNU C/C++ is to install CygWin: http:// www.cygwin.com. We’ll start with a very simple GNU C++ project. Suppose we already have some files for this project: ❑
board.h — The header for the Board class.
❑
board.cpp — The definition of the Board class.
❑
queens.cpp — The main() function.
On my system these files are in the directory Z:\ProfessionalSlickEdit\projects\gnu_queens. The code for this project is included on the accompanying CD-ROM. The listing for board.h follows: #include class Board { public: Board(int size); int size(); void place(int row, int col); int unplace(int row); bool is_ok(int row, int col); bool solve(); int col(int row); private: int size_; std::vector pos_; std::vector col_; std::vector diag1_; std::vector diag2_; };
The listing for board.cpp is below: #include “board.h” Board::Board(int size) : size_(size), pos_(size, -1), col_(size, false), diag1_(2*size+1, false), diag2_(2*size+1, false) { } int Board::size() { return size_; }
47
22150c04.qxd:WroxPro
9/25/07
12:26 AM
Page 48
Part II: Using SlickEdit void Board::place(int row, int col) { pos_[row] = col; col_[col] = true; diag1_[col-row+size_] = true; diag2_[col+row] = true; } int Board::unplace(int row) { int col = pos_[row]; pos_[row] = -1; col_[col] = false; diag1_[col-row+size_] = false; diag2_[col+row] = false; return col; } bool Board::is_ok(int row, int col) { return !(col_[col] || diag1_[col-row+size_] || diag2_[col+row]); } bool Board::solve() { int row = 0; int col = 0; while (row >= 0 && row < size_) { while (col < size_ && !is_ok(row, col)) { col++; } if (col < size_) { place(row, col); row++; col = 0; } else { row--; if (row >= 0) { col = unplace(row) + 1; } } } return row == size_; } int Board::col(int row) { return pos_[row]; }
Finally, the driver program is in queens.cpp: #include #include #include #include
“board.h”
int main (int argc, char *argv[]) {
48
22150c04.qxd:WroxPro
9/25/07
12:26 AM
Page 49
Chapter 4: Workspaces and Projects if (argc < 2) { std::cerr delimiters are treated as PHP. As well as getting different syntax coloring, most other syntax assistance features also work for the embedded language. It may not be clear in the printed book, but here SlickEdit displays the comments in green, keywords in orange, the string in turquoise, and the rest of the text in black.
Figure 9-36
Client-side JavaScript is often placed into its own .js file, which SlickEdit treats just like any other source file. JavaScript may also be embedded within HTML files, within the tag. In this case, SlickEdit supports the embedded syntax between the tag and its closing tag. Figure 9-37 shows an example of JavaScript embedded in an HTML file. Again, the main file is treated as HTML. The text within the and tags is treated as JavaScript, getting syntax coloring and other language-specific assistance.
Figure 9-37
‘Here Documents’ in Scripts UNIX shells, and several scripting languages, support multiline strings called here documents. These are extremely convenient for templates that output code, such as HTML or SQL.
191
22150c09.qxd:WroxPro
9/25/07
1:25 AM
Page 192
Part II: Using SlickEdit Here documents begin with
248
22150c11.qxd:WroxPro
9/25/07
1:29 AM
Page 249
Chapter 11: Aliases and File Templates
249
22150c11.qxd:WroxPro
9/25/07
1:29 AM
Page 250
Part II: Using SlickEdit
This is a simple build script, including basic steps for compiling production and test code and running tests. In a real environment, you would also include standard targets for packaging and possibly distributing your application, and other targets too. Note that the template uses substitution parameters for the copyright, user, and local date as before. We also use the predefined substitution parameter $projectname$ to set the Ant project name from the name given to the project in SlickEdit. This can, of course, be changed after the template is instantiated.
2. # # # #
Create an accompanying build.properties file, with this content: $$Id$ $copyright$ $username$ $localdate$
Chapter 11: Aliases and File Templates 4. 5. 6. 7.
Create a new file template category “Java,” under User Templates. In the Java category, create a template called Ant build file. In the template, set the name, description, and default name to Ant build file. Link the template to the three source files build.xml, build.properties, and build.number .properties.
Now that we have the template, the next step is to cause the custom project type to instantiate it when creating a new project. We will extend the custom project created in Chapter 4, with the InitMacro named wrox_create_java_dirs(). In the Author/Chapter11 directory on the CD-ROM is an updated version of that macro, called wrox_create_java_project(). The code is shown below: _command int wrox_create_java_project() name_info(‘,’) { // create src/java/com/wrox/ _str java_path = _file_path(_project_name) :+ “src” :+ “java” :+ FILESEP :+ “com” :+ FILESEP make_path(java_path); // create src/test/com/wrox/ _str test_path = _file_path(_project_name) :+ “src” :+ “test” :+ FILESEP :+ “com” :+ FILESEP make_path(test_path);
The new statement, containing the add_item() call, should all be on one line. The function call instantiates the Ant build file template from the user templates directory and adds the files to the current project. Note that the add_item() macro function detects the environment variable %VSLICKCONFIG% and replaces it with your SlickEdit configuration directory. Load this code, and change the InitMacro to refer to the new name. The next time you create a new project of type Java Project — WROX, you should get it initialized with the standard build scripts, as well as the source directories. The add_item() macro used here is the same command that is invoked from the menu via File ➪ Add New Item from Template. When invoked from the menu, the macro displays the Add New Item dialog. If you use the macro from Slick-C code, you can provide parameters, as we’ve done here, to bypass the dialog. As with a number of SlickEdit macro/commands, the parameters are not documented in the Help system, but they are not difficult to figure out by reading the source code. Reading the Slick-C source code is essential for making significant extensions and customizations. Sometimes when browsing the Slick-C macro source code you will find that a command works by calling some other, simpler macro function. Or, you may discover the internal workings of some mechanism, such as the XML structure of configuration files. You can use this knowledge in your own programming
251
22150c11.qxd:WroxPro
9/25/07
1:29 AM
Page 252
Part II: Using SlickEdit when appropriate. However, remember that the internal workings can change from release to release. The more your own code relies on low-level functionality and implementation details, the more likely it is to break between releases. Try to use higher-level functionality and documented commands and functions as much as possible, as they are less likely to change.
Summar y In this chapter, we looked at two related features that allow you to add your own customized time-savers to SlickEdit. Aliases are useful for a wide variety of situations, from shorthands for commonly used files and directories, to full-sized coding constructs, including overriding the built-in syntax expansion. The inline macro execution capability of aliases is particularly powerful for advanced uses. File templates are useful when you want to define a standard boilerplate layout for one or more files. The difference comes down to a matter of granularity. Aliases are pieces of code; templates are one or more files. In the next chapter, we cover several topics relating to document types.
252
22150c12.qxd:WroxPro
9/25/07
1:32 AM
Page 253
Document Types When you open a file in SlickEdit, the editor determines several things about it. We’ve already seen the importance of the extension in determining the document mode. (The mode is basically the programming language family; see Chapter 9.) Most programming language source files are simple ASCII files (or nearly enough), and that is all that matters. SlickEdit can also edit files of other types. Sometimes there is more involved in determining how to read them or display them. SlickEdit can open binary files. For binary files, it’s usually more useful to view them in hex mode as bytes rather than as text characters. Sometimes hex mode is useful for text files too. SlickEdit supports XML files as well. XML files are Unicode rather than ASCII and can be represented on disk in a variety of encodings. Unicode is a massive character set (~100,000 characters). This introduces some challenges, because most fonts are not capable of displaying the entire set. When dealing with XML documents, SlickEdit’s default behavior is to try to provide as much assistance as it can by downloading referenced DTDs and schemas from the Internet. I use a laptop for almost all my work, and because I’m on the road a lot, not always connected to the Internet, sometimes I don’t want this behavior. Sometimes I need to prevent SlickEdit from fetching documents from the Internet. An even better option is to store local copies of required resources and get SlickEdit to use them instead. In this chapter, we cover a variety of topics concerning types of files and ways to view and edit them.
Document Mode When you open a source file with a known extension, SlickEdit places the document into the mode associated with the extension. If SlickEdit does not recognize the extension, the editor goes into Fundamental mode. Usually the automatically selected mode is just what you want, because it enables all the features associated with the programming language.
22150c12.qxd:WroxPro
9/25/07
1:32 AM
Page 254
Part II: Using SlickEdit Sometimes you don’t want the features enabled, or you want a different mode. For example, syntax expansion features can get in the way when using Macro Record and Playback. You can use select-mode (Document ➪ Select Mode) to select a different mode for the editor. You can also switch modes using specific commands for each mode. The mode switching commands are simply the name of the mode followed by -mode. For example, the command to switch to Fundamental mode is fundamental-mode, and the command to switch to HTML mode is html-mode. An example in which this mode-switching is useful is in Ruby on Rails views, which are .rhtml files containing a mixture of HTML and Ruby code. SlickEdit supports some combinations of HTML and scripting languages (such as ASP and JavaScript), but not HTML and Ruby. However, you can get some of the benefits of both languages by switching between HTML and Ruby modes while editing the file. We gave some examples of working with embedded languages in Chapter 9.
Binar y F iles When you open a binary file, SlickEdit attempts to display it as text by default. For binary files, this is usually meaningless. To view a binary file, switch to hex mode using the hex command (View ➪ Hex or Ctrl+Shift+H). SlickEdit displays the file as 16-byte chunks as shown in Figure 12-1. You can still edit the text part on the right-hand side, or you can edit the hexadecimal representation by clicking in the lefthand side. To switch back to text mode, invoke hex again.
Figure 12-1 SlickEdit also supports Line Hex mode via the linehex command (View ➪ Line Hex). Line hex mode shows each “line” of the source file on a separate line in the editor, showing both ASCII characters and hex bytes. This mode is useful if you have a file that has line structure but binary data. An example might be a PDF file. Hex mode can be useful for text mode too, occasionally. For example, you can use it to check line endings in a file when you are not sure if the file has UNIX or DOS line endings (or might have both). You can use it to check tab characters in makefiles.
Character Sets and Encodings Before Unicode became popular, all source code editors used code pages to edit source files. Originally, SlickEdit could only edit code page source files like the other source code editors. There are some advantages to code page editors. Code page editors do not need to translate the bytes in your file when you open the file. This has some speed advantages, allows for a single editor storage format that can display the bytes in your file as lines of text or in hex, and guarantees that there are no translation errors. The
254
22150c12.qxd:WroxPro
9/25/07
1:32 AM
Page 255
Chapter 12: Document Types disadvantage of code page editors is that realistically you can’t edit Unicode files. This is because there is no code page that contains all the characters in the Unicode character set. Now that Unicode is widely used for XML and other text files, code page editing is not enough. Today, most source code editors that support Unicode files convert code page files to an internal Unicode representation (usually UTF-16 or UTF-8). All Microsoft text editors, including Visual Studio, do this. In order to retain the advantages of code page editing for those files for which it is suitable, SlickEdit has two basic in-memory representations: ❑
Single Byte Character Set/Double Byte Character Set (SBCS/DBCS) — SBCS/DBCS mode means code page editing. In this mode, the text in your file is not translated except for EBCDIC, which is a slight variant of this mode because characters are translated to ASCII.
❑
Unicode (represented internally as UTF-8) — This is typically used for XML. In this mode, if the data in your file are not already in UTF-8, SlickEdit will translate them into UTF-8.
SlickEdit normally determines the encoding and thus the character set automatically, based on the file extension and content. If the file extension is associated with XML, the file is loaded as Unicode. If the file contains a Unicode Byte Order Mark (BOM), also known as a signature, the BOM determines the encoding, and the file is loaded as Unicode. Otherwise, the file is loaded as SBCS/DBCS. You can override the encoding on the Open dialog. Most of the encodings require your files’ text to be converted to UTF-8, but some are for SBCS/DBCS mode. The Windows “Fast” Open dialog, or “Windows 3.1 style” Open dialog, does not have an option to override the encoding. If you need to override the encoding when opening a file on Windows, you need to switch to the standard Open dialog. It is important to understand the distinction between Unicode and SBCS/DBCS when working with XML files, because some features are not fully supported for the Unicode representation. For example, hex mode is not supported for XML files in encodings other than UTF-8, because the disk representation is different from the in-memory representation. If you need to view a UTF-16 XML document in hex, for example, you need to open it using an SBCS/DBCS encoding, such as Binary. Several other features, mainly concerning limitations of fonts, are also not supported for Unicode. These are documented in the online Help. You can use the encoding option in the Open dialog to create a new file in a specific encoding. For example, you can create a text file using UTF-16 encoding. When you save the file, SlickEdit stores a UTF-16 BOM at the beginning, and writes two bytes per character.
XML Document Types XML files are often described using a Document Type Definition, or DTD, which is a specification describing the valid content of files of the given type. The DTD specifies which elements the document may contain, what content the elements may contain, whether they are mandatory or optional, their attributes, and so forth. An XML document that conforms to its DTD is said to be valid. In 2001, the W3 Consortium introduced the XML Schema standard as a new and more powerful way to describe content rules for XML documents. XML Schema is used by many modern XML systems, including most of those in Web Services, such as SOAP and WSDL.
255
22150c12.qxd:WroxPro
9/25/07
1:32 AM
Page 256
Part II: Using SlickEdit When SlickEdit opens an XML file that references a DTD or schema, the editor loads the document definition so that it can validate the document structure and provide syntax assistance. If the document is not valid, SlickEdit displays error messages in the Output tool window and also highlights unknown elements using the configured Unknown XML Element color. In order to validate a document, SlickEdit needs to refer to the DTD or schema. Usually the DTD or schema is given by a URL. For example, the URL for the DTD for configuration files for the Spring framework is http://www.springframework.org/dtd/spring-beans-2.0.dtd. This downloading can take a noticeable time, even if you are on a fast network. If you are behind a firewall or not connected to the network, the downloading fails after a timeout. During this time the editor is effectively hung, and you cannot work. One solution to this issue is to store a copy of the DTD/schema on your local hard disk and refer to that copy instead. Let’s configure SlickEdit to refer to a local copy of the Spring configuration DTD. On my system, the framework is installed in C:\lib\spring-framework-2.0.2. Follow these steps:
1.
Open the URL Mappings dialog (Tools ➪ Options ➪ URL Mappings). SlickEdit displays the dialog, shown in Figure 12-2.
Figure 12-2
2. 3. 4. 5.
Click Add. SlickEdit adds a new empty entry. Enter http://www.springframework.org/dtd/spring-beans-2.0.dtd for From. Enter C:\lib\spring-framework-2.0.2\dist\resources\spring-beans-2.0.dtd for To. Click OK. SlickEdit adds the URL mapping.
After adding this URL mapping, SlickEdit retrieves the DTD from the local disk instead of over the network. Locally mapped URLs are stored in options.xml in your SlickEdit configuration directory. When setting up URL mappings, SlickEdit’s support for multiple clipboards is helpful. You can copy the From and To parts into the clipboard in turn, then use list-clipboards (Ctrl+Shift+V) to paste them selectively into the URL Mappings dialog.
256
22150c12.qxd:WroxPro
9/25/07
1:32 AM
Page 257
Chapter 12: Document Types If you don’t have a local copy of the DTD or schema and you are working offline, you may prefer to disable SlickEdit’s document validation, so that you can open files quickly, without timeouts. The autovalidation setting is in the XML Formatting Options dialog, reached from the XML Options button on the Extension Options dialog for XML (Tools ➪ Options ➪ File Extension Setup). Turning off auto-validation prevents SlickEdit from validating XML documents when it opens them. You can still validate them manually at any time by invoking the xml-validate command. Even with auto-validation turned off, SlickEdit still tries to download the DTD or schema, so that it can use it to provide syntax expansion and color highlighting. You can prevent SlickEdit from downloading DTDs or schemas for syntax expansion by adding extensions to the def_xml_no_schema_list macro variable. For example, enter this command: set-var def_xml_no_schema_list .xml .xsd
This command disables automatic download of DTDs and schemas for syntax expansion for all XML and XSD files. You can enable syntax expansion and color highlighting for a specific file you have open by invoking apply-dtd-changes. You can also invoke this command by right-clicking in the window and clicking “Apply DTD, TLD, or Schema Changes.” For the best editing experience with XML files, I recommend that you download all DTDs and schemas referred to by your documents and store local copies on your hard drive. Use the URL mapping configuration to prevent SlickEdit from downloading them from the Internet every time it opens a file. Here is a macro and function you can use to automate downloading URL resources and creating local mappings for them: _command void wrox_make_url_mapping(url) name_info(‘,’) { edit(url); // Note: SlickEdit knows how to fetch http:// addresses _str resourcename = wrox_make_local_resource_filename(); save(resourcename); quit(); typeless handle=_cfg_get_useroptions(); int index = _xmlcfg_set_path(handle,”/Options/URLMappings”); int new_index = _xmlcfg_add(handle, index, “MapURL”, VSXMLCFG_NODE_ELEMENT_START, VSXMLCFG_ADD_AS_CHILD); _xmlcfg_set_attribute(handle, new_index, “From”, url); _xmlcfg_set_attribute(handle, new_index, “To”, resourcename); _cfg_save_useroptions(); } _str wrox_make_local_resource_filename() { int i = 0; _str basename = _config_path() :+ “resource”; while (file_exists(basename :+ i)) { i++; } return basename :+ i; }
257
22150c12.qxd:WroxPro
9/25/07
1:32 AM
Page 258
Part II: Using SlickEdit To use this macro to download the Spring configuration DTD to a local copy, load the macro and enter this command on the SlickEdit command line: wrox-make-url-mapping http://www.springframework.org/dtd/spring-beans-2.0.dtd
The macro uses a function, wrox_make_local_resource_filename(), which returns an unused filename in the SlickEdit configuration directory. The function uses the SlickEdit-provided function _config_path() to get the configuration directory. It then works by simply appending numbers to the prefix resource until it finds a name that does not currently exist as a file in the configuration directory. The macro uses SlickEdit’s ability to fetch HTTP resources when passed to the edit command. You don’t need to do anything else to load an HTTP resource into SlickEdit. It’s not industrial strength: There’s no error-handling, so you won’t use it for building your next Web Services infrastructure, but for automating some manual tasks in the editor, it will do just fine. After loading the resource, the macro saves it to the new file. Finally, it uses some of SlickEdit’s XML handling functions to open the options.xml configuration file and add the URL mapping.
Summar y In this chapter, we have covered several areas loosely gathered under the topic of document types. Firstly, the document mode determines much of the appearance and behavior of the editor, particularly for files having syntax highlighting and assistance. In Chapter 17, some examples of defining new document modes for your own languages are demonstrated. SlickEdit can open files in a variety of character sets and encodings, including binary files. Finally, most of the chapter was concerned with XML document types and effective ways to manage DTDs and XML schemas for working with these. In the next chapter, we take a look at SlickEdit’s Compare and Merge tools, which are used for managing and comparing different versions of files and directories.
258
22150c13.qxd:WroxPro
9/25/07
1:34 AM
Page 259
Comparing and Merging For some reason or another, we programmers always seem to end up with multiple, slightly different versions of the same file. Or worse — multiple, slightly different versions of the same source tree. Now, one thing I’ve noticed in my career is that this has been happening a lot less since I started using version control. Proper use of version control reduces the need for archived or backup copies of source code, or copies of the same source tree all over your disk. We look at version control in more detail in the next chapter. Of course, it still happens. (Usually when it happens to me, it means I haven’t been using version control properly!) This must be a fairly common occurrence for programmers, and perhaps other computer users too, because there are several commercial tools on the market whose sole function is to compare directories and files and resolve the differences. Happily, if you already own SlickEdit, you probably don’t need one of those tools, because SlickEdit has great file and directory comparison and merging built right in. You can even run SlickEdit’s comparison tools outside the editor, as a full replacement for standalone tools for the same purpose. In this chapter, we’ll take a look at comparing and merging files and directories. We’ll also take a look at some basic versioning capabilities built into SlickEdit.
Comparing F iles and Directories SlickEdit’s file and directory comparison tool is called DIFFzilla. You can use DIFFzilla to compare buffers with each other, buffers with files, or files with other files. You can also use it to compare entire subdirectories of your file system.
22150c13.qxd:WroxPro
9/25/07
1:34 AM
Page 260
Part II: Using SlickEdit
Comparing Two Files Suppose that, in a fit of performance-tuning enthusiasm, we re-wrote the gnu_queens program to use old style C arrays instead of STL collections. We have a copy of the old source code in a separate backup directory. Let’s use DIFFzilla to examine the differences between the STL board.h and the arrays board.h. Follow these steps:
1.
Invoke diff (Ctrl+equals). SlickEdit displays the DIFFzilla setup dialog, shown in Figure 13-1. You use this dialog to set up the files or directories you wish to compare.
Figure 13-1
2.
Enter the path and filename of the old version of board.h in Path 1. You can use the button labeled “…” to select the file from the file system. You can use the button labeled “B” to select an open buffer.
3. 4.
Enter the path and filename of the new version of board.h in Path 2. Click OK. SlickEdit displays the Diff window, shown in Figure 13-2.
The differences in the file are indicated graphically. You can navigate backward and forward among the differences using the Next Diff and Prev Diff buttons. The most common use of DIFFzilla is simply to compare two versions of a file. However, you can also use DIFFzilla to resynchronize files by eliminating differences. The first row of buttons in the Diff window provides operations for copying lines or blocks from either side to the other. You can save either side at any time while you are working in the Diff window, and you can undo changes. In fact, the two buffer panes act like the regular SlickEdit editor pane in most ways, so you can type and make use of a limited set of SlickEdit editing features, such as cursor movement and syntax assistance. Not all commands work by default in the Diff window. If you try to use a command that is not supported in Diff, you will receive a message box stating “Command ‘xxx’ currently not allowed in Diff mode.” For example, you cannot use selections to copy lines directly from one pane to the other, or within a pane. You can use the clipboard to copy selections, however.
260
22150c13.qxd:WroxPro
9/25/07
1:34 AM
Page 261
Chapter 13: Comparing and Merging
Figure 13-2
The Diff window uses its own command dispatch mechanism. The commands that are supported are listed in the diffedit.e macro file supplied in the macros directory under the SlickEdit installation. If you want to add additional commands, you can add them there. Use caution when making changes to supplied macros. Changes to the supplied macros can affect the behavior of the editor. For example, while the standard prev-word and next-word commands are supported in DIFFzilla, the WROX alternatives wrox-prev-whitespace-word and wrox-next-whitespace-word are not. To add them, follow these steps:
1. 2.
Edit diffedit.e. Add these lines near the top of the file, to declare prototypes for the commands:
Invoke load. You should now be able to use wrox-prev-whitespace-word and wrox-next-whitespace-word in DIFFzilla editor panes.
This tip can work for your own commands and for many standard SlickEdit commands that have been omitted from DiffCommands, for whatever reason. Thanks to Hartmut Schaefer (hs2) for this tip.
261
22150c13.qxd:WroxPro
9/25/07
1:34 AM
Page 262
Part II: Using SlickEdit
Comparing Sections within a File Sometimes, instead of comparing entire files, you need to compare only a range of lines. Occasionally you may need to compare ranges of lines within a file. For example, here is a fragment from an XML schema definition: ... Purpose - Define a partial address. Detail - This type allows the transfer of portions of an address. Where a complete address is to be transferred, the Address type should be used. ... Purpose - Define an address. Detail - The address format allows for either a structured or an unstructured physical address, with locality, state and postcode always being carried as structured elements.
262
22150c13.qxd:WroxPro
9/25/07
1:34 AM
Page 263
Chapter 13: Comparing and Merging ...
To limit the comparison to a range of lines, click the More button under Path 1 in the DIFFzilla setup dialog. Like most of SlickEdit, the DIFFzilla functionality is available via a macro function. The diff command invokes DIFFzilla and has many options. Most of the options are documented in the online Help, and the rest, corresponding to options available in the setup dialog, can be discovered by looking at the source code in diff.e. Here’s an example of using DIFFzilla from a macro to save work. When comparing ranges of lines, it is rather tedious to note the line numbers for the starts and ends of the ranges and enter them into the DIFFzilla setup dialog. This macro can make comparing ranges of lines a bit easier: _command void wrox_diff_lines(_str bookmarks = “1 2 3 4”) name_info(BOOKMARK_ARG’*,’VSARG2_REQUIRES_EDITORCTL) { _str bookmark1; _str bookmark2; _str bookmark3; _str bookmark4; parse bookmarks with bookmark1 bookmark2 bookmark3 bookmark4; push_bookmark(); goto_bookmark(bookmark1); _str filename1 = p_buf_name; int start_line1 = p_line; goto_bookmark(bookmark2); if (p_buf_name != filename1) { message(“Bookmark 2 must be in same file as bookmark 1.”); pop_bookmark(); return; } int end_line1 = p_line; if (end_line1 len) { result = substr(string, length(string) - len + 1, len); } else { result = translate(indent_string(len - length(string)), pad, ‘ ‘) :+ string; } return result; }
And here are a couple of examples of using these functions: wrox_assert_equals(“http”, wrox_leftstr(“http://www.skepticalhumorist.co.nz”, 4)); wrox_assert_equals(“000123”, wrox_rightstr(“123”, 6, “0”));
317
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 318
Part III: Advanced SlickEdit Parsing Strings Slick-C uses a powerful and unusual construct for parsing strings, which it borrowed from the IBM mainframe scripting language REXX. If you have worked with scripting languages, you are probably used to using regular expressions for string parsing. Slick-C provides the parse with keywords for string parsing. Here’s an example: _str s = “2007-05-19”; _str yyyy, mm, dd; parse s with yyyy’-‘mm’-‘dd; wrox_assert_equals(“2007”, yyyy); wrox_assert_equals(“05”, mm); wrox_assert_equals(“19”, dd);
The parse with construct uses a template or pattern to parse a string, placing matches or parts into variables. The parse with construct can be used for many situations in which you have to parse a string into parts according to a pattern. One of the most common cases is parsing command arguments. If you write a function that takes two string parameters, you would declare it like this: void foo(_str a, _str b) { // ... }
However, this is not necessarily the best way to declare a command that takes two string parameters. When invoking functions, arguments are separated by commas. With commands, arguments are usually separated by spaces. It’s friendlier to the user of a command if it is declared like this: _command void wrox_try_parse_command(_str s=”“) name_info(‘,’) { _str a, b; parse s with a b; // ... }
The user can invoke this command like this: wrox-try-parse-command one two
If the arguments can contain spaces, you will need to do something more elaborate to parse them, because SlickEdit does not automatically parse quotation marks in command-line arguments. A common technique is to use parse with to extract repeated items from a string: _str s = “1,2,3”; _str head, rest; int i = 0; parse s with head’,’rest; while (head != “”) { wrox_assert_equals(++i, head); parse rest with head’,’rest; } wrox_assert_equals(3, i);
318
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 319
Chapter 16: Slick-C Macro Programming Although literal strings and output variables are the most common features used in parse with templates, several other features are supported. Table 16-2 shows the elements that can be contained in the template.
Table 16-2 Item
Description
variable_name
Output variable.
.
Null output variable (match ignored).
nnn
New parse column.
+nnn
Parse column increment.
-nnn
Parse column decrement.
‘text‘[,search_options]
String constant or pattern to search for.
(expression)[,search_options]
String expression to search for.
The numeric offsets let you control the character positioning of parsing. The parenthesized expression feature allows you to use a variable in the template, including a variable that has been set earlier in the template. For example: _str date1 = “2007/5/19”; _str yyyy, mm, dd, delim; parse date1 with yyyy +4 delim +1 mm (delim) dd; wrox_assert_equals(2007, yyyy); wrox_assert_equals(5, mm); wrox_assert_equals(19, dd); _str date2 = “2008-12-01”; parse date2 with yyyy +4 delim +1 mm (delim) dd; wrox_assert_equals(2008, yyyy); wrox_assert_equals(12, mm); wrox_assert_equals(1, dd);
The search options allow you to use regular expressions for parts of the template. The search options can be one or more of the characters in Table 16-3. Here’s an example of parsing with a regular expression: _str url = “http://www.skepticalhumorist.co.nz/index.html”; _str host; _str file; parse url with “(http|ftp)“,”U” “://“ host “/“ file; wrox_assert_equals(“www.skepticalhumorist.co.nz”, host); wrox_assert_equals(“index.html”, file);
319
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 320
Part III: Advanced SlickEdit Table 16-3 Character
Description
B
Brief-style regular expression.
I
Case-insensitive match.
R
SlickEdit-style regular expression.
U
UNIX-style regular expression.
Y
Binary value for DBCS searches (see online Help).
Using regular expressions with parse with is useful up to a point. But there’s no way to use regular expressions in conjunction with storing a result in an output variable. Suppose you want to parse a date and ensure that its components are numeric. The example above does not check this and thus would parse “20XX/may/twentieth,” for example, possibly giving a type conversion error later in the macro. The pos() function can be used for more complex parsing scenarios. The ordinary use of pos() is the familiar string function that returns the position of a substring in a search string: wrox_assert_equals(6, pos(“th”, “The other ones”)); wrox_assert_equals(1, pos(“th”, “The other ones”, 1, “I”)); // case-insensitive wrox_assert_equals(6, pos(“th”, “The other ones”, 3, “I”)); // with start pos
The fourth argument to pos() is a set of options, which includes the options available for patterns in parse with. You can call pos() with a single argument to find the positions and lengths of matched subexpressions when using regular expressions. Call pos(“S1”) to get the start position of the first matched subexpression and pos(“1”) to get its length: _str date = “2007-05-20”; wrox_assert_equals(1, pos(‘(\:d{4})([-/])(\:d{1,2})\2(\:d{1,2})‘, date, 1, “U”)); wrox_assert_equals(2007, substr(date, pos(“S1”), pos(“1”))); wrox_assert_equals(5, substr(date, pos(“S3”), pos(“3”))); wrox_assert_equals(20, substr(date, pos(“S4”), pos(“4”)));
A new utility function is planned for SlickEdit 2008 to simplify this idiom: get_match_substr(). As well as the pos() function, Slick-C also provides the lastpos() function, which has the same arguments but works backward from the end rather than forward from the start: wrox_assert_equals(6, lastpos(“th”, “The other ones”, “”, “I”));
Arrays Slick-C arrays look like C arrays, but, in fact, they are dynamic, which is much more convenient for a scripting language. Whenever you set an element of an array, Slick-C ensures that the array is long enough. For example, you can append items to an array like this: _str a[]; a[a._length()] = “one”;
Arrays have several built-in member functions defined for them, which are declared in builtins.e. For example, you can sort an array like this: a._sort(); wrox_assert_equals(“four”, a[0]); wrox_assert_equals(“one”, a[1]); wrox_assert_equals(“three”, a[2]); wrox_assert_equals(“two”, a[3]);
There are several other functions that also take arrays as arguments. For example, there are the join() and split() functions, borrowed from Perl: _str a[]; a[a._length()] = “one”; a[a._length()] = “two”; a[a._length()] = “three”; a[a._length()] = “four”; wrox_assert_equals(“one,two,three,four”, join(a, ‘,’)); _str b[]; split(“five,six,seven,eight”, “,”, b); wrox_assert_equals(“five”, b[0]); wrox_assert_equals(“six”, b[1]); wrox_assert_equals(“seven”, b[2]); wrox_assert_equals(“eight”, b[3]);
Note that Slick-C’s split() function only works with exact strings for splitting, not regular expressions.
Hash Tables Hash tables are also known in other languages as dictionaries, maps, or associative arrays. They let you store keys and values. You can also use a hash table as a simple set by storing a dummy value against each key. The Slick-C syntax for declaring and accessing hash tables is similar to that for arrays: _str h:[]; h:[“first”] = “one”; h:[“second”] = “two”; h:[“third”] = “three”; wrox_assert_equals(“one”, h:[“first”]); wrox_assert_equals(“two”, h:[“second”]); wrox_assert_equals(“three”, h:[“third”]);
321
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 322
Part III: Advanced SlickEdit If you want to iterate over the elements in a hash table, the syntax is a little stranger, because you have to use a typeless iterator for the keys and use several built-in functions for the iteration: typeless k; _str a[]; for (k._makeempty();;) { h._nextel(k); if (k._isempty()) { break; } a[a._length()] = k :+ “:” :+ h:[k]; } a._sort(); wrox_assert_equals(“first:one”, a[0]); wrox_assert_equals(“second:two”, a[1]); wrox_assert_equals(“third:three”, a[2]);
If you’re like me, you probably find this idiom for iterating through items in a hash table a little weirdlooking. At the very least, it’s a little verbose. Future versions of Slick-C may provide a more natural way of iterating through hash tables. In fact, a foreach statement is tentatively planned for SlickEdit 2008. In the meantime, you can make things a little bit nicer for your own code by adding a function to return the keys as an array: typeless wrox_hash_keys(typeless h:[], boolean sorted = true) { typeless k; typeless result[]; for (k._makeempty();;) { h._nextel(k); if (k._isempty()) { break; } result[result._length()] = k; } if (sorted) { result._sort(); } return result; }
Using this function, you can iterate through the items of a hash table by looping over its keys. The snippet below shows the function in action. Note that hash table keys are not sorted normally. (This is normal for hash data structures.) The convenience function wrox_hash_keys() sorts the result by default before returning it. _str b[] = wrox_hash_keys(h); wrox_assert_equals(“first”, b[0]); wrox_assert_equals(“second”, b[1]); wrox_assert_equals(“third”, b[2]);
322
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 323
Chapter 16: Slick-C Macro Programming Structs Structs are familiar to C programmers, and a similar language feature is available in most other languages. Slick-C structs are much the same as in C. struct NAMES { _str first_name; _str last_name; };
As with arrays and hash tables, you can declare and initialize structs globally: NAMES name = { “John”, “Hurst” };
You can use structs to build up arbitrarily complex data structures: struct NAMES_LIST { NAMES head; NAMES_LIST tail; };
However, be aware that in Slick-C, assignment is a deep copy (not a shallow reference copy such as in languages like Java). This example would therefore be a very inefficient way to implement a linked list, because adding an item would copy the whole list, unless the code is careful to traverse to the end of the list using pointers and then add the new item.
Typeless Container Variables As seen with hash table iterators, Slick-C supports a typeless type. Variables declared as typeless can hold values from any type, including structs, arrays, and hash tables. If you need to, you can determine the actual type of value currently stored in a typeless variable using its _varformat() member function, declared in builtins.e. The function returns one of the VF_ constants defined in slick.sh. _str wrox_typeless_type(typeless v) { switch (v._varformat()) { case VF_ARRAY: return “ARRAY”; case VF_EMPTY: return “EMPTY”; case VF_FREE: return “FREE”; // shouldn’t happen! case VF_FUNPTR: return “FUNPTR”; case VF_HASHTAB: return “HASHTAB”; case VF_INT: return “INT”; case VF_LSTR: return “LSTR”; case VF_PTR: return “PTR”; default: return “UNKNOWN”; }
323
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 324
Part III: Advanced SlickEdit } _str a[]; a[0] = “one”; a[1] = “two”; typeless e = null; _str h:[]; h:[“one”] = 1; h:[“two”] = 2; int i = 1; _str s = “Hello”; wrox_assert_equals(“ARRAY”, wrox_assert_equals(“EMPTY”, wrox_assert_equals(“HASHTAB”, wrox_assert_equals(“INT”, wrox_assert_equals(“LSTR”,
The documentation for _varformat() warns that its behavior is likely to change in a future version of SlickEdit, thus you should be wary of using it. SlickEdit 2008 adds classes and changes the implementation of structs. In SlickEdit 2008, there is a new _varformat(), VF_OBJECT, which represents a struct or class instance.
Control Structures Slick-C control structures are basically the same as in C, with a few minor enhancements because of the more dynamic nature of Slick-C. Whenever you create a block, it creates a new scope for local variables. This is the same as most modern C-style languages. This does allow you to re-use the same name for a new variable in a new scope: int x = 1; { int x; x = 3; } wrox_assert_equals(1, x);
However, such usage is confusing and is not recommended. It’s treated as a compilation error if you are using #pragma option(strict, on). The if() statement is straightforward: int i = random(0, 10); if (i < 5) { wrox_assert(i < 5); } else { wrox_assert(i >= 5); }
324
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 325
Chapter 16: Slick-C Macro Programming The for() statement is usually used for loops involving a known number of iterations: int sum = 0; int i; for (i = 0; i < 10; i++) { sum += i; } wrox_assert_equals(45, sum);
Some people also like to use the for() loop for an unknown number of iterations: for (;;) { // loop “forever” if (random(0, 10) < 1) { break; } }
The while() statement is more commonly used for loops with an unknown number of iterations, when the loop condition should be tested before executing the first iteration: _str head, rest = “1,2,3”; int i = 0; parse rest with head’,’rest; while (head != “”) { wrox_assert_equals(++i, head); parse rest with head’,’rest; } wrox_assert_equals(3, i);
If the loop always should be executed at least once, the do() statement places the condition test at the end: _str head, rest = “1,2,3”; int i = 0; do { parse rest with head’,’rest; if (head != “”) { wrox_assert_equals(++i, head); } } while (head != “”); wrox_assert_equals(3, i);
Unlike most compiled languages, the Slick-C switch() statement can use strings as case targets, which is a great convenience: _str month = “May”; int mm; switch (upcase(month)) { case “JANUARY”: mm = 1; break; case “FEBRUARY”: mm = 2; break; case “MARCH”: mm = 3; break;
325
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 326
Part III: Advanced SlickEdit case “APRIL”: mm = 4; break; case “MAY”: mm = 5; break; case “JUNE”: mm = 6; break; case “JULY”: mm = 7; break; case “AUGUST”: mm = 8; break; case “SEPTEMBER”: mm = 9; break; case “OCTOBER”: mm = 10; break; case “NOVEMBER”: mm = 11; break; case “DECEMBER”: mm = 12; break; default: message(“Unknown month: “month); _StackDump(); } wrox_assert_equals(5, mm);
You should note that switch() using strings is really a syntactic convenience. The Slick-C compiler currently does not generate a jump table for switch statements.
Declarations and Definitions A Slick-C module is made up of declarations and definitions. In this section, we’ll cover how you declare some elements of Slick-C programs: ❑
Functions.
❑
Commands.
❑
Variables.
❑
Event Tables.
Functions We’ve already seen many examples of function definitions in this book. A definition includes the full function body. You can also write function declarations. A declaration includes the name, arguments, and return type of the function. Declarations are also known as prototypes and are commonly placed in header files. The purpose of declarations is to give the compiler more information about functions so that it can catch more errors at compile time. By default, Slick-C resolves function references at run time; thus it is legal to make use of any Slick-C function in code without declaring it. There is no check at compile time whether the function actually exists. While this is convenient and typical in dynamic languages, it does mean that you can accidentally mistype a function name and the compiler will not inform you of your error. Instead, the error will manifest itself at run time when Slick-C attempts to invoke the function. As of SlickEdit 12.0.2, you can enforce declaration checks using this #pragma at the top of your file: #pragma option(strictprotos, on)
With this option, a prototype declaration or full definition is required before any use of a function.
326
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 327
Chapter 16: Slick-C Macro Programming Because Slick-C does not support overloaded functions, you can define any given function name only once. This is not a limitation in practice because default arguments and variable arguments are supported; thus it is possible to simulate overloaded functions by treating arguments flexibly. Specify default arguments by assigning them in the function signature, like this: _str wrox_leftstr(_str string, int len, _str pad=’ ‘) { // ... }
If you specify a default for any argument, all the arguments after that must also have default arguments. Specify variable arguments with “…” in the function signature, like this: void wrox_multimessage(_str m, ...) { _str messages = m; int i; for (i = 2; i < arg(); i++) { messages = messages “\n” arg(i); } _message_box(messages); }
When you use variable arguments, access them using the arg() function. Call the arg() function with no arguments to get the total number of arguments to the current routine. Call arg() with an argument number to retrieve that argument. Default arguments are a newer feature in Slick-C than variable arguments. In older code, you may find variable arguments being used when defaults would be more appropriate. For example, an alternative way to implement wrox_leftstr() using variable arguments is shown here: _str wrox_leftstr(_str string, int len, ...) { _str pad = ‘ ‘; _str result = ‘’; if (arg() >= 3) { pad = arg(3); } if (length(string) > len) { result = substr(string, 1, len); } else { result = string :+ translate(indent_string(len - length(string)), pad, ‘ ‘); } return result; }
In this case, the previous implementation using default arguments is clearer, and there is no need for variable arguments in defining wrox_leftstr(). Use variable arguments when you have a truly variable number of arguments, rather than simply optional arguments, which are better handled with default values.
327
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 328
Part III: Advanced SlickEdit Commands Commands can be bound to keys or run on the command line; ordinary functions cannot. Another difference between commands and ordinary functions is that the naming rules are relaxed for commands; thus they can include special characters not normally allowed in function names. This is how the names for some of the special SlickEdit commands work. For example, the find command is declared like this: _command int find,l,’/‘(argument list) { ...
Thus, “L” and the slash are valid alternative names for the command. The same feature applies in a similar way to the goto-line command (the shorthand is simply typing the desired line number as a command), and commands for moving up or down a given number of lines (the shorthands are “-” and “+”). However, this feature is not something you are likely to use in your own commands. The underscore character is commonly used in Slick-C identifiers. Commands containing underscores are displayed with the underscores changed to hyphens and can be entered that way too. Commands are defined the same way as functions, with some differences. Command definitions are preceded by the _command keyword, and they optionally have a name_info() expression after the argument list. The _command keyword simply indicates that the definition is a command. The optional name_info() expression specifies types of arguments accepted by the command, and the valid context for it. The name_info() expression is a string consisting of two parts, separated by a comma. The first part specifies the type of argument for the command, which is used on the command line to provide argument completion. It should be an _ARG value from slick.sh. Some of the most useful argument values are shown in Table 16-4.
Table 16-4 Argument Value
Description
COMMAND_ARG
The command takes a SlickEdit command name as an argument.
BOOKMARK_ARG
The command takes a bookmark name as an argument.
FILE_ARG
The command takes a filename.
DIR_ARG
The command takes a directory.
TAG_ARG
The command takes a tagged procedure.
SlickEdit uses the argument information to provide completion for command arguments. For example, if you specify FILE_ARG for your command, SlickEdit can complete filenames on the command line for
328
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 329
Chapter 16: Slick-C Macro Programming it. Append an asterisk (*) character to the argument parameter if the command can take one or more arguments. You can make your commands prompt for their arguments using the handy prompt() function defined in stdprocs.e. Suppose you have a command that takes a filename argument. Write the command like this: _command void wrox_try_prompt_filename(_str filename=”“) name_info(FILE_ARG’,’) { filename = prompt(filename, “Filename”); // ... rest of command }
If the user types the command name, presses Space, and starts typing a filename, SlickEdit’s completion features help the user complete the filename. If the user types just the command name and presses Enter, SlickEdit prompts on the command line for the “Filename” parameter. Because of the name_info() specifying a file argument, prompt() supplies auto-completion for the filename. SlickEdit commands such as name and edit use this facility. If your command takes a command-name argument, you can write it like this: _command void wrox_try_prompt_command(_str command=”“) name_info(COMMAND_ARG’,’) { command = prompt(command, “Command”); // ... rest of command }
This time prompt() auto-completes command names, because name_info() specifies a command argument. The second part of the name_info() expression specifies the valid context for the command and should be a combination of VSARG2_ values from slick.sh. Some of the common ones are shown in Table 16-5.
Table 16-5 Argument Value
Description
VSARG2_CMDLINE
The command is supported on the command line.
VSARG2_EDITORCTL
The command is supported in an editor control.
VSARG2_READ_ONLY
The command is allowed in read-only mode.
VSARG2_REQUIRES_EDITORCTL
The command requires an editor control.
VSARG2_REQUIRES_AB_SELECTION
The command requires a selection in the active buffer.
VSARG2_REQUIRES_SELECTION
The command requires a selection.
329
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 330
Part III: Advanced SlickEdit For example, consider the wrox-save-line-sel command given in Chapter 8. The purpose of the command is to save the given line selection as a pair of bookmarks. The definition has a name_info() expression specified like this: _command void wrox_save_line_sel(_str bookmark = “SELECTION”) name_info(‘,’VSARG2_REQUIRES_AB_SELECTION) { // ... }
The second part of the name_info() expression is VSARG2_REQUIRES_AB_SELECTION, which indicates that the command requires a selection in the active buffer. If you have a buffer open, but no selection, SlickEdit displays the message “Command is disabled for this object.” Only when the conditions are valid will SlickEdit execute the command. Both parts of the name_info() expression are optional, as is the whole expression. If you leave either part out, it simply means that SlickEdit is less able to provide help with the arguments and context of your command. This is often not a big deal for user-written macros, but it is certainly a good feature for many of the SlickEdit-provided commands. The VSARG2_ constants cover a variety of standard contexts for commands. For scenarios that aren’t covered by these standard contexts, you can write a callback function to determine whether a command is valid. The callback function’s name should be the command’s name prefixed by _OnUpdate_. For example, a callback for wrox-save-line-sel would be declared: int _OnUpdate_wrox_save_line_sel() { // ... }
The callback should return MF_ENABLED if the command is allowed and MF_GRAYED if the command is not allowed. (These constants are declared in slick.sh.)
Global Variables If you declare a variable outside any function, it is global and is shared across the entire Slick-C environment. If you want to share a global variable across multiple Slick-C modules, it’s best to declare it in a header file, then #include that header file in any module that needs to reference the global variable. You still need to define and initialize the global variable in a specific module. That module “owns” the global variable.
Static Variables If you declare a variable outside a function but use the static keyword in the declaration, the variable is static but not global. A static variable is visible to any code in the module (i.e., the current .e file). If you declare a static variable with the same name in two different files, each has its own copy of the variable. Use static variables for global data within a module, and use global variables for global data that need to be shared across different modules.
Macro Variables Macro variables refer to Slick-C variables containing configuration settings to control SlickEdit features. Most of the macro variables’ names start with def_.
330
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 331
Chapter 16: Slick-C Macro Programming Technically, macro variables are just global Slick-C variables. Most of them are declared in slick.sh. Some commands work specifically with macro variables, by filtering on the def_ naming convention. For example, list-config lists the contents of macro variables but not other global variables.
Event Tables Event tables are special declarations that are used primarily to bind commands to shortcut keys. There is a default event table, called default_keys. There is also an event table for each language mode, such as c_keys, java_keys, and xml_keys. Definitions for specific modes override the defaults in default_keys. There are also event tables for certain special modes in the editor, shown in Table 16-6.
Table 16-6 Event Table Name
Description
argument_completion_keys
Argument completion.
auto_complete_keys
When Auto-Complete active.
fileman_keys
File Manager.
grep_keys
Search Results tool window.
process_keys
Process Buffer.
To specify key bindings for an event table, first specify the desired event table using defeventtab. Then define key bindings using def: defeventtab html_keys; def ‘A-/‘= wrox_insert_html_ending_tag;
You should always specify an event table using defeventtab, but if you don’t, the default is default_keys. We cover programmatic key binding with event tables more in Chapter 17. More information on event tables can also be found in the “Slick-C Macro Programming Guide.”
Wor king with Macros The above sections have covered some of the elements of the Slick-C language and common routines. In this section, we take a look at techniques for working with macros themselves: the mechanics of executing them, terminating them, and debugging them. You should find some of this information useful when you are developing or debugging your own macro code.
331
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 332
Part III: Advanced SlickEdit
Executing Slick-C Code When you are developing macro code, you will want to run it frequently. The normal way to run some Slick-C code is to invoke a command. You can obviously test your macros by running them on the command line or by binding commands to keys. If you have several different commands and functions, it may not be feasible to set up key bindings for them all, but command retrieval on the command line is often an effective way to test macro code repeatedly. If you have a set of lines in the buffer, containing SlickEdit commands, you can execute them by selecting them and invoking execute-selection (Alt+equals). It’s not exactly a graphical debugger, but it’s pretty handy for quick macro development. If you are working on a command and wish to execute it, the execute-selection command is not the fastest way. You need to have the command name by itself on a line in the buffer to use execute-selection, and this is not usually the case. (For one thing, if you put it in the same .e file as the command you’re working on, the file becomes invalid to compile.) Instead, you can try this macro: _command void wrox_execute_current_command() name_info(‘,’VSARG2_REQUIRES_EDITORCTL|VSARG2_READ_ONLY) { execute(current_proc()); message(“Command [“current_proc()“] executed successfully.”); }
If you bind this command to a key, you can execute the Slick-C command you are editing at any time. For example, I have it bound to Alt+Shift+equals, which is easy to remember because it is similar to Alt+equals (the default binding for execute-selection). This works well for commands that have no arguments.
Terminating a Macro If your macro goes into an endless loop or is running for too long for any other reason, you can halt it by pressing the macro break key combination: Ctrl+Alt+Shift+F2. For some reason, I found this key combination really hard to remember for years. You might want to write it down somewhere just in case, because if you need it, you really need it.
Writing Messages A fundamental technique for debugging in all programming languages is outputting debug messages from your code. Slick-C provides several built-in ways to display debug messages. You can display a message in the message area of the editor using the message() function: message(“Hello, World.”);
This function can be used in debugging but is also commonly used for ordinary status messages. Be aware that as soon as another routine calls message(), the previous message will be replaced. Therefore, message() is not suitable for complex debugging with a lot of messages. It can be quite handy for simple debugging though.
332
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 333
Chapter 16: Slick-C Macro Programming The messageNwait() function is a variation that pauses after displaying the message and waits for the user to press a key: messageNwait(“Hello, World.
Press a key to continue.”)
This function is very useful for debugging because it causes a refresh so that you can see where the cursor is and what changes have been made to the file at each point where you call messageNwait(). If you want to display a message more dramatically, you can use _message_box() instead. This pops up a message box with the given message. The user must dismiss the message box by clicking OK before the calling macro continues. _message_box(“Hello, World.”);
These functions for displaying a message are occasionally useful for debugging but are also quite valid for normal use in macros. Finally, there is the say() function, which really is just for debugging: say(“Hello, World.”);
This function also takes its name from the REXX equivalent. The say() function outputs its messages to the vsapi.dll output window on Windows, as shown in Figure 16-2. On UNIX, it writes to stdout, and on Mac OS X, output is written to a console log, for example, /Library/Logs/Console/501/ console.log.
Figure 16-2
If you see the vsapi.dll window appear while using SlickEdit and you haven’t put any debug code into macro files yourself, it usually means you’ve hit some debug code of the SlickEdit team. There are plenty of references to say() in the supplied sources, but most of them are intended to be invoked only in debugging scenarios.
Stack Traces Consider the command wrox-makestacktrace, shown below. The command calls the wrox_ stacktrace1() function, and this function calls the wrox_stacktrace2() function. The wrox_stacktrace2() function contains an illegal expression, where it attempts to add 1 to a null value. This results in SlickEdit aborting the function and displaying a stack trace. _command void wrox_makestacktrace() name_info(‘,’) { wrox_stacktrace1(); } void wrox_stacktrace1() { wrox_stacktrace2();
333
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 334
Part III: Advanced SlickEdit } void wrox_stacktrace2() { _str a = arg(1) + 1; }
SlickEdit displays the stack trace in the Slick-C Stack tool window, shown in Figure 16-3.
Figure 16-3
You can programmatically update the Slick-C Stack tool window by calling _UpdateSlickCStack() in your code. You can dump the stack to the console debug output (vsapi.dll, stdout, etc.) at any time by calling _StackDump(). Finally, if you get a stack dump due to an error, the stack dump is also written to a log file (vs.log in your configuration directory). You can navigate to any frame of the stack trace in the Slick-C Stack tool window by moving the cursor to the line and pressing Enter, or by double-clicking. If you note the offset reported in the stack trace, you can also navigate to it directly in the module using the st command with the –f option. For example, in Figure 16-3, the first stack frame is in wrox_stacktrace.ex at offset 67. To navigate to the corresponding source line, you can open wrox_stacktrace.e and invoke this command: st -f 67
Usually the cause of a stack trace is pretty clear from the source code combined with the error message.
Finding Slick-C Objects If you need to find a particular Slick-C command or function, use the find-proc command (shorthand fp). The command opens the module in which the function is defined and navigates to the definition. You can use this command at any time — you don’t have to be working in a Slick-C file or workspace. The Slick-C environment stores all global objects in a single name table. The name table holds the names of all functions, commands, variables, and other objects. In macro code, you can find out about objects in the Slick-C global namespace using the find_index() function. For example, you can test whether a command with a given name exists like this: if (find_index(command, COMMAND_TYPE)) { message(“Command “command” exists.”); }
334
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 335
Chapter 16: Slick-C Macro Programming else { message(“Command “command” does not exist.”); }
You can find objects matching a given name prefix using the name_match() function. The function takes a prefix for the names you want to match, a flag to indicate first match or next match, and flags to indicate the kinds of objects you are interested in. It returns an index into the global names table, or 0 if nothing is found. You can then use the name_name() and name_type() functions to find out about the symbol given its index. For example, you can use this function to obtain an array of name indexes of objects matching given criteria: typedef int INTARRAY[]; INTARRAY wrox_find_matching_name_indexes(_str prefix, int name_type_flags) { int result[]; int index = name_match(prefix, 1, name_type_flags); while (index) { result[result._length()] = index; index = name_match(prefix, 0, name_type_flags); } return result; }
This snippet illustrates the usage of the function: int indexes[]; indexes = wrox_find_matching_name_indexes(“cursor_“, COMMAND_TYPE|PROC_TYPE); wrox_assert_equals(7, indexes._length()); wrox_assert_equals(“cursor-down”, name_name(indexes[0])); wrox_assert_equals(“cursor-up”, name_name(indexes[1])); wrox_assert_equals(“cursor-left”, name_name(indexes[2])); wrox_assert_equals(“cursor-right”, name_name(indexes[3])); wrox_assert_equals(“cursor-error2”, name_name(indexes[4])); wrox_assert_equals(“cursor-error”, name_name(indexes[5])); wrox_assert_equals(“cursor-shape”, name_name(indexes[6]));
The names table holds information about objects other than commands and functions. For example, it holds all the global variables too. You can query the value of an integer or string global variable with a given name like this: int index = find_index(varname, VAR_TYPE); if (!index) { message(“Variable “varname” not found.”); return; } if (index) { typeless value = _get_var(index); message(varname”=[“value”]“); // integer or string only! }
335
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 336
Part III: Advanced SlickEdit The types of objects you can query in the names table are defined in slick.sh and shown in Table 16-7.
Table 16-7 Type
Description
PROC_TYPE
Matches global function.
VAR_TYPE
Matches global variable.
EVENTTAB_TYPE
Matches event table.
COMMAND_TYPE
Matches command.
MODULE_TYPE
Matches module.
PICTURE_TYPE
Matches picture.
BUFFER_TYPE
Matches buffer.
OBJECT_TYPE
Matches object.
MISC_TYPE
Matches miscellaneous.
IGNORECASE_TYPE
Matches case-insensitive search.
You can use the name_match() function with these types to find out more about objects in the Slick-C environment. For example, you can list all loaded modules using this command: _command void wrox_try_list_modules() name_info(‘,’) { int index = name_match(“”, 1, MODULE_TYPE); while (index) { insert_line(name_name(index)); index = name_match(“”, 0, MODULE_TYPE); } }
The command’s output includes all modules: user-defined and SlickEdit-supplied. If you want to know the names of all the modules you have loaded, you can get them from the macro variable def_macfiles. This contains a space-delimited list of filenames of all .ex files loaded by the user.
Useful Techniques The previous section concerned techniques for working with macros themselves: various ways of executing and debugging them. Now we turn our attention to how you can actually put macros to use to perform useful tasks in SlickEdit. In this section, we cover several common techniques for using macros to do things in the editor.
336
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 337
Chapter 16: Slick-C Macro Programming
Interacting with the Buffer One of the most fundamental things you need to do in a Slick-C macro is interact with the buffer. Obviously, all the commands we’ve looked at elsewhere in the book and in this chapter are accessible to any Slick-C macro. There is no shortage of ways for a macro to move around the buffer and to move and copy text. Sometimes a macro needs to be able to examine the text in the buffer, and macros often need to be able to enter text themselves. A macro can read text from the buffer using the primitive function get_text().The get_text() function returns a chunk of text from the buffer. It takes two arguments: a character count and a seek position, both of which are optional: get_text(10, 8); // gets 10 characters from position 8 get_text(10); // gets 10 characters from the cursor position get_text(); // gets the character at the cursor position
The default value for the seek position is a special negative value, which causes the function to use the current cursor position. The default value for the character count is 1. Thus, get_text() with no arguments returns the character at the current cursor position. The get_text() function is particularly useful when combined with search(), as explained below. A macro can also retrieve the current line from the buffer using the get_line() function. The function retrieves the line into the variable given as an argument: _str the_line; get_line(the_line); // retrieves current line into var
To insert text, a macro can use the _insert_text() function: _insert_text(“;”);
// inserts a semicolon at the cursor position
Alternatively, macros can insert whole lines using the insert_line() function: insert_line(“end;”); // adds line after current line
A macro can also delete text from the buffer using the _delete_text() function: _delete_text(10); _delete_text(-1); _delete_text(-2);
// deletes 10 characters // deletes to end of line // deletes to end of buffer
You can also delete the entire current line with _delete_line(). There is also a delete_line() command (no leading underscore), but this is not usually appropriate for general macro use because it is hooked into the auto-unsurround feature.
Searching It’s frequently useful in a macro to search for text in the buffer. You can invoke the find command, which is the same as the slash (/) command on the command line. However, this command is intended for interactive use and is not generally used internally by macro code. If you invoke find in your macro, it
337
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 338
Part III: Advanced SlickEdit may have unintended side effects. For example, find changes the search performed by find-next, and it can change the selection too. Usually, a macro shouldn’t affect these features unless that is its specific purpose. Instead, you can invoke the lower-level search() function from macro code, which is not available directly as a command. Invoking search() in your macro code is less disruptive to the user’s environment because it doesn’t affect the same settings that find does. In fact, you can study the implementation of find: It uses search() internally. The search() function is built in and is not implemented in Slick-C. The search() function returns a status that indicates the success of the search. A status of 0 indicates a successful search; other statuses indicate that nothing was found or that there was a problem with the search criteria. To write a macro that does something for each match, follow this pattern in your code: int status = search(string, options); while (!status) { // do something at the search match status = repeat_search(); }
Many of the same options you would use with find on the command line are also useful with search() in macro code, such as + and – to search forward and backward, m to search in the selection, and so forth. A couple of options you should consider using with search() specifically in macro code are h and @. The h option causes search() to find text in hidden lines as well as visible lines. This can make your macros more robust, in case selective display happens to be active when the macro is running. The @ option prevents search() from displaying an error message if nothing is found. If you are testing the result of search() in your macro code, you can decide in the macro whether it is an error if nothing is found. Usually it is not an error, but just another possible scenario for the macro to deal with. If your search uses a regular expression with tagged subexpressions, you can extract the text matching the subexpressions from the editor using get_text() with match_length(), as shown in this example: int status = search(“created date.*(\\:d{4}-\\:d{1,2}-\\:d{1,2})“, “UI”); if (!status) { message(“Created date = “get_text(match_length(“1”), match_length(“S1”))); }
This example code searches for the text “created date,” followed by a date in ISO format (yyyy-mm-dd). If a match is found, the macro shows the date in the message area. The U option indicates that the search is for a UNIX-style regular expression, and the I option makes it case-insensitive. The macro extracts the date from the editor using the get_text() function. The match_length() function returns character counts and seek positions suitable for get_text(). When match_length() is called with a string representing a tagged subexpression group number, for example, “1,” it returns the length of the match on that subexpression. When match_length() is called with an “S” followed by a group number, it returns the seek position for the match on that subexpression. Thus get_ text(match_length(“1”), match_length(“S1”)) means the text in the buffer matched by the first tagged subexpression. Similarly, you can use “2” and “S2” for the second subexpression, and so forth. If you specify “0” and “S0,” you get the entire matched text.
338
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 339
Chapter 16: Slick-C Macro Programming There is a convenient utility function, get_match_text(), which is a shorthand for get_text() with match_length(): message(“Created date = “get_match_text(“1”));
You can use save_search() and restore_search() to save and restore the current search data. This allows you to write functions that use search but do not disturb existing searches, so that you can nest one search in another search. Here is an example from the save_search() documentation: search(‘test’); save_search(string, options, word_re); status = search(‘xyz’); if (status) { messageNwait(“Can’t find xyz”); } restore_search(string, options, word_re); // Repeats search for ‘test’ repeat_search();
Selections Macros can allocate and use multiple selections, activating them as required. Several primitive functions exist for managing selections. They are well documented in the online Help, under the category “Selection Functions.” To get the selection type of the active selection, use the _select_type() function with no arguments. The result is “BLOCK,” “CHAR,” or “LINE” according to the selection type, or a null string if no selection is active. To iterate over a line selection, use the filter_init(), filter_get_string(), and filter_restore_pos() functions like this: filter_init(); for (;;) { _str line; int status = filter_get_string(line); // fetch next line into variable if (status) { break; // status is non-zero when no more lines } // do something with the line } filter_restore_pos();
Temporary Buffers A common requirement in more elaborate macros is to have a “scratch pad” buffer to place results while the macro is working. We’ll see one application of this in the next section, where we find out how to work with lists of files and directories. The situation arises often in the supplied macro source code, and SlickEdit supplies some functions specifically for creating and managing temporary buffers.
339
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 340
Part III: Advanced SlickEdit One advantage of using a special temporary buffer rather than simply opening a new empty file is that the temporary buffer is not displayed while your macro is running. This snippet illustrates the use of the _create_temp_view(), _delete_temp_view(), and activate_window() functions to work with a temporary buffer: int temp_view_id; int orig_view_id = _create_temp_view(temp_view_id); // do something with the temporary buffer ... _delete_temp_view(temp_view_id); activate_window(orig_view_id);
You can open an existing file in a temporary buffer with _open_temp_view(). The advantage of this in a macro, rather than opening the file normally using edit(), is that the buffer is hidden. This lets you open a file, do something, and close it, without the user seeing the activity on screen.
Listing Files and Directories We’ve already mentioned that I/O in Slick-C is different from that in most programming languages. Rather than opening a file, reading its contents in some kind of loop, and then closing it, you simply load the file into a buffer and work on it in the buffer. Listing files and directories is similar. Rather than using special I/O functions to iterate through lists of files and directories, SlickEdit provides the built-in function insert_file_list(), which simply inserts names and attributes of files and directories into the buffer. You can then work with the list in the buffer as required. The insert_file_list() function takes a single string argument, which contains the filespec for files to insert, but also can contain several additional options. Most of the options are single letters preceded by + or -, to turn on or off certain features. These are documented in the online Help, and the more common ones are also shown in Table 16-8. In addition, the string argument can include -exclude with a list of file patterns to exclude.
Table 16-8
340
Option
Description
H
Includes hidden files (Windows only). Default is ON in Windows if Explorer is set to show all files.
S
Includes system files. Default is ON in Windows if Explorer is set to show all files.
Recursive: includes files in subdirectories. Default is OFF.
U
Includes UNIX dot files. Default is ON.
V
Verbose output with size, date, attributes. Default is ON.
By default, files are listed with their sizes, dates, and attributes, as with the DOS dir command. You can omit the extra information and list the file names only with –V. For example, to list macro source files into the buffer, including their paths but excluding other attributes, you could use this code: _str macro_filespec = maybe_quote_filename(get_env(“VSLICKMACROS”) :+ ‘*.e’); insert_file_list(‘ +P -V -D ‘ macro_filespec);
Often when dealing with lists of files and directories, the desired end result is not to see them listed in a buffer but to actually do something with them. The following simple function lists files and returns them in an array, rather than leaving them in a buffer. This makes it a little more natural for calling macro code to iterate through the list of files. The function takes a single argument, almost identical to that for insert_file_list(). STRARRAY wrox_list_files(_str command) { int filelist_view_id; int orig_view_id = _create_temp_view(filelist_view_id); _str result[]; insert_file_list(“-V “command); top(); up(); while (!down()) { _str filename; get_line(filename); filename = strip(filename); if (filename == “”) { break; } result[result._length()] = maybe_quote_filename(filename); } _delete_temp_view(filelist_view_id); activate_window(orig_view_id); return result; }
This function uses a couple of the techniques we’ve looked at. First, it creates a temporary buffer. Then it lists files into the temporary buffer using the supplied criteria. Notice that it adds –V to the criteria, to limit the output to filenames only, suppressing other attributes. This function is not intended to list other attributes.
341
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 342
Part III: Advanced SlickEdit The main part of the function iterates through each line in the temporary buffer, adding the contents of the line to the result array. Before an item is added to the result array, the function calls maybe_quote_ filename() on it to ensure that it is quoted if it contains spaces. This is one reason the macro wouldn’t work with additional data such as size, date, and attributes. They would be surrounded by quotes, which would not be appropriate. If you need a version of wrox_list_files() that includes size, date, and attributes, you can expand on this function, possibly using a struct to store the results.
Choosing Files When you want to allow the user to choose one or more files for your macro to process, you can present a customized File Open dialog using the Slick-C _OpenDialog() function. The function takes several arguments, documented in the online Help. Here’s an example: _command void wrox_try_open_dialog() name_info(‘,’) { _str files = _OpenDialog( “-modal _open_form”, // form and mode “Choose files to list”, // title “*.e;*.sh”, // initial exts “All Files (*.*),C/C++ Files (*.c;*.cpp;*.h),Slick-C Files (*.e;*.sh)“, OFN_ALLOWMULTISELECT|OFN_FILEMUSTEXIST, // flags “”, // default ext “”, // initial filename “” // initial directory ); while (files != “”) { _str file; parse files with file files; insert_line(file); } }
This command shows some of the options to _OpenDialog() in action. It prompts the user to select one or more files, and then lists their names in the buffer. By using different arguments, you can specify defaults and limit the types of files to be selected. You can also specify a callback that the _OpenDialog() function will call before presenting a list, so that you can screen the files being offered to the user. There are many examples of _OpenDialog() in the supplied macro source.
Useful Macro Files Most of the supplied macro source deals with specific SlickEdit functionality. When you are interested in a particular feature, it is usually not hard to find the source file(s) containing code pertaining to that feature. For example, CVS-related code is unsurprisingly located in cvs.e, cvsquery.e, and cvsutil.e. The commands and functions supporting the Ruby language are in ruby.e. There are several files that contain useful global declarations or general-purpose functions. We’ve already discussed most of these files and many of their declarations in this chapter. You may find it useful to peruse some of these files in more detail, for example, to discover additional code not described in this book. Table 16-9 lists some of the most useful general-purpose macro files in the supplied source.
Built-in functions and properties. Includes operations for arrays and hashes, some basic window and menu functions, global properties, and low-level (primitive) functions. All of these functions and properties are implemented natively. The builtins.e file only declares them: There is no Slick-C implementation.
main.e
Declares many macro variables, provides default values.
stdcmds.e
Defines many standard commands, e.g., undo, redo, nosplit-insert-line, begin-line, top-of-buffer.
stdprocs.e
Defines many standard functions, e.g., abs(), strip_filename(), maybe_quote_filename(), path_exists(), _create_temp_view(), _delete_temp_view().
util.e
Defines more standard commands, e.g., scroll-up, scroll-down, center-line, sort-on-selection, asc, chr, execute-selection, goto-line, select-mode, block-insert-mode. Quite useful for seeing how these work.
Callbacks Callbacks are Slick-C functions you write that SlickEdit will call whenever certain events occur. For example, you can have a callback that is invoked whenever a project is opened. You create callbacks by writing Slick-C functions following a certain naming convention. Callback functions are named _event_name(), where: ❑
_event_ is the name of the callback event, and
❑
name is a name you give to the function to make it unique and to indicate its purpose.
Callback event names start with an underscore, and almost always end with one too. For example, here is a callback function from Chapter 5, which pops all bookmarks whenever a workspace is closed: void _wkspace_close_popallbkms() { pop_all_bookmarks(); }
The event name for this callback is _wkspace_close_, and what the callback does is indicated by the popallbkms part of the function name. The _wkspace_close_ callback takes no arguments. Some callbacks can be provided with arguments giving more information about the event. For example, there is a _buffer_renamed_ event that occurs when a buffer is renamed. Callbacks for _buffer_renamed_ are provided with four arguments: ❑
Buffer ID.
❑
Old name.
343
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 344
Part III: Advanced SlickEdit ❑
New name.
❑
Flags.
You can write a callback to be called whenever a buffer is renamed, using this signature: void _buffer_renamed_wrox_example(buf_id, old_name, new_name, buf_flags) { // your code here ... }
Table 16-10 shows some of the callback events available in SlickEdit 12.0.2, with a description for each and a list of the arguments provided to the callback. A more complete listing is in Appendix C.
Table 16-10
344
Name
Event
Arguments
_actapp_
Application activated (such as getting focus).
Whether getting focus.
_buffer_add_
New buffer opened.
Buffer ID, buffer name, buffer flags.
_buffer_renamed_
Buffer renamed.
Buffer ID, buffer name, new name, buffer flags.
_cbquit_
About to quit file.
Buffer ID, buffer name, filename, buffer flags.
_cbquit2_
After quit file.
Buffer ID, buffer name, filename, buffer flags.
_cbsave_
File saved.
(none)
_cbstop_process_
Stopping build.
(none)
_cd_
Directory changed.
New directory.
_diffOnExit_
End of DIFFzilla operation.
(none)
_diffOnStart_
Start of DIFFzilla operation.
(none)
_document_renamed_
Document name changed.
Buffer ID, old name, new name, buffer flags.
_eventtab_modify_
Key bound.
Key binding table, key.
_gotfocus_
Received focus.
(none)
_lostfocus_
Lost focus.
(none)
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 345
Chapter 16: Slick-C Macro Programming Table 16-10 (continued) Name
Event
Arguments
_onexit__
Exit.
(none)
_postbuild_
Build completed.
Build arguments.
_prebuild_
Build about to start.
Build arg 1 (see source in compile.e).
_prjclose_
Closing project (but fired only if not saving state during auto restore … see source in wkspace.e).
(none)
_prjconfig_
Active configuration changed.
(none)
_prjedit_
Project properties edited.
(none)
_prjopen_
Opening project.
(none)
_prjupdate_
Project saved.
(none)
_project_close_
Closing project.
Project name.
_project_file_add_
File added to project.
Project name, filename.
_switchbuf_
Switching buffer.
Old buffer name, option, old pos, old buffer ID.
_wkspace_close_
Closing workspace.
(none)
_workspace_file_add_
File added to workspace.
Project name, filename.
_workspace_opened_
Opening workspace.
(none)
SlickEdit looks up and invokes callbacks using the call_list() function defined in files.e in the supplied macro source. By examining references to call_list(), you can find all the places in SlickEdit where callbacks are invoked, what they are called, and what arguments are supplied. For example, when you use the name command to rename a buffer, eventually during the execution of this command, the name_file2() function is called, defined in files.e. The name_file2() function looks like this: int name_file2(_str new_name) { call_list(‘_buffer_renamed_‘,p_buf_id,p_buf_name,new_name,p_buf_flags); p_buf_name= new_name; docname(“”); return(0); }
345
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 346
Part III: Advanced SlickEdit The function does three things: ❑
It calls all callbacks whose names start with _buffer_renamed, passing the buffer ID, the old buffer name, the new buffer name, and the buffer flags.
❑
It changes the buffer name (p_buf_name) to the new name.
❑
It resets the document name by calling docname(“”). (The document name is used when the display name of a buffer is not a valid filename, e.g., for http:// files.)
If you want to understand the context and parameters of a particular callback better, you need to study the Slick-C code invoking the callback. You can search for a callback identifier from Table 16-10 using Find in Files, or you can search references to the call_list() function to find all places where callback events are dispatched. One interesting way to study the behavior of callbacks is to set up tracing for them. For example, if you load this code, it will output a message to the vsapi.dll window whenever the _switch_buffer event occurs: void _switchbuf__trace() { say(“_switchbuf_ called”); }
You can generate similar trace code for other events. In the “Example Macros” section below, we give a macro that can generate trace calls like this for all callbacks defined in SlickEdit.
Example Macros This chapter has contained a small amount of definitions and theory about Slick-C, but most of the focus has been on practical use of Slick-C for macro programming. In this section, we give several examples of more elaborate macros. These examples put the techniques together to make complete applications. As with the rest of this book, these examples are supposed to be practical and useful. (Well, most of them.) But the main point of them is to show how you can customize and extend SlickEdit for your own needs. In years of using SlickEdit, I’ve written many macros specifically for work I was doing at the time. In some jobs, I’ve worked with obscure scripting file formats with no tool support. I wrote SlickEdit macros to provide the support I needed. In another job, I worked for a client whose C++ coding style standard was, I believe, unique in the world. I created SlickEdit macros to “beautify” my code into his style. Any time you find yourself doing repetitive editing, consider whether it can be automated with Slick-C. You will often find that writing a Slick-C macro takes less time than editing the tedious way. It’s more fun, too. And, as with everything, the more you do of it, the faster and better you become. SlickEdit is the kind of tool that really rewards long-time use and investment. As with other source code presented in this book, the full source for these examples is on the accompanying CD-ROM, under /Author/Chapter16. Updates and bug fixes are also available online.
346
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 347
Chapter 16: Slick-C Macro Programming
Example: Counting Duplicate Lines SlickEdit has a nice command for removing adjacent duplicate lines in a selection: remove-duplicates. Occasionally, as well as removing the duplicates you need to know how many there were. The macro command below removes duplicates and appends the counts for each line to the end of the line: _command void wrox_count_duplicates(_str ignore_case = “”) name_info(‘,’VSARG2_REQUIRES_EDITORCTL|VSARG2_REQUIRES_AB_SELECTION) { if (_select_type() :!= “LINE”) { message( “Command needs a line mark” ); return; } ignore_case = upcase(ignore_case) == “I”; // initialize variables int entry = 0; _str key[]; int data[]; key[entry] = “”; data[entry] = 0; int max_keylen = 0; int max_datalen = 0; // go through marked lines filter_init(); for (;;) { _str line; int status = filter_get_string(line); if (status) { break; } boolean matched = ignore_case ? strieq(key[entry], line) : key[entry] :== line; if (matched) { // duplicate: increment count data[entry]++; if (length(data[entry]) > max_datalen) { max_datalen++; } } else { // new entry: add to table, start count at 1 if (data[entry] > 0) { entry++; } key[entry] = line; if (length(line) > max_keylen) { max_keylen = length(line); } data[entry] = 1; } }
347
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 348
Part III: Advanced SlickEdit filter_restore_pos(); // delete the selection delete_selection(); cursor_up(); // insert the aggregate (formatted neatly) int i; for (i = 0; i < key._length(); i++) { insert_line(wrox_left(key[i], max_keylen) :+ “ “ :+ wrox_rightstr(data[i], max_datalen)); } }
This macro uses the filter_selection() functions to iterate through the selection. It stores the lines themselves in the key[] array and the counts in the data[] array. When outputting the revised lines, it uses the wrox_leftstr() and wrox_rightstr() functions from above in this chapter to pad the results. Another nice feature is that if there are no duplicate lines, then the macro adds no counts — it effectively leaves the data unchanged. Suppose you run this command with a selection containing these data: one two two three three three ten ten ten ten ten ten ten ten ten ten
The result looks like this: one 1 two 2 three 3 ten 10
Like SlickEdit’s remove-duplicates command, this command takes an optional string parameter which, if “I,” causes the macro to compare lines case-insensitively.
Example: Inserting HTML End Tag SlickEdit has considerable HTML and XML support these days, and more is added with every release. For example, when you type a start tag such as
or
, SlickEdit automatically adds the end tag, usually in the correct place and indented to your preferences. However, for whatever reason, I still find
348
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 349
Chapter 16: Slick-C Macro Programming that I often delete the end tags inserted by SlickEdit, then need to type them in again, perhaps in a different location. Some IDEs and other products automatically insert closing tags when you type the 1, “basefont” => 1, “bgsound” => 1, “br” => 1, “frame” => 1, “hr” => 1, “img” => 1, “input” => 1, “isindex” => 1, “link” => 1, “meta” => 1, “nextid” => 1, “param” => 1, “plaintext”=> 1, “spacer” => 1, “wbr” => 1 }; _command void wrox_insert_html_ending_tag() name_info(‘,’MACRO_ARG2|MARK_ARG2) { _str tagexp = ‘]*)>’; int nesting = 0; int status = 0; int start_line = p_line; int start_col = p_col; push_bookmark(); status = search(tagexp, “U 0 && tag == nesting_stack[nesting - 1]) { // matched start: pop it nesting--; }
349
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 350
Part III: Advanced SlickEdit } else { // otherwise end-tag not optional if (nesting == 0) { // a start tag with zero nesting; we’re done break; } else { if (tag == nesting_stack[nesting - 1]) { // matched nested end-tag nesting--; } else { // unmatched message(“Found unmatched tag ”); return; } } } } status = repeat_search(); } // end while if (status) { message(“Couldn’t find a tag.”); return; } int tag_line = p_line; int tag_col = p_col; pop_bookmark(); _str line; get_line(line); line = strip(line); if (p_line != tag_line) { // match is on different line from cursor: insert_line(“”); // add a new line for end tag p_col = tag_col; } _insert_text(“”); // insert the end tag }
The macro tries to insert the appropriate closing tag at the current location. It searches backward for opening and closing tags, keeping a stack of tags it has found. When it encounters a closing tag, it pushes it on the stack. When it encounters an opening tag, it pops the stack and matches it with the top of the stack. If it finds an unexpected opening tag, it reports an error. When it encounters an opening tag and there’s nothing left to pop, that’s the tag that needs to be ended. The macro inserts a closing tag in the buffer. If the start tag is on the same line as the cursor position, the macro inserts the closing tag at the cursor position. Otherwise, it adds a new line and inserts the ending tag indented to the same level as the start tag. XML rules are very strict: In XML, all opening tags must be matched with closing tags. HTML, particularly older HTML, is more lax. Some tags are often specified as “opening” tags with no closing tags. Common examples of tags like this are and . The macro has special processing to be tolerant of these tags if they are not closed. Suppose you start with a file like this: Title
350
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 351
Chapter 16: Slick-C Macro Programming
Paragraph.
Paragraph. xxx
one
If your cursor is after the “one” on the last line and you invoke wrox-insert-html-ending-tag eight times, the macro will fill in the ending tags, indented correctly, like this: Title
Paragraph.
Paragraph. xxx
one
To be effective, this macro should be bound to a key. I usually have it bound to Alt+slash, in HTML and XML modes.
Example: Moving Lines Up and Down I often find that I want to change the order of lines in the buffer. The usual way to do this is to use copy and paste, or perhaps to mark a line selection and move it. These methods are a little awkward for reordering a lot of lines. The macros below can be used to move lines up or down conveniently in the buffer. If there is a character or line selection, the macros move the selection; otherwise, they move the current line. For a character selection, the macros first convert it to a line selection, using the wrox-to-lineselection command: _command void wrox_to_line_selection() name_info(‘,’) { push_bookmark(); begin_select(); push_bookmark();
351
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 352
Part III: Advanced SlickEdit end_select(); if (p_col == 1) { cursor_up(); } select_line(); pop_bookmark(); select_line(); pop_bookmark(); }
The move commands themselves are given below: _command void wrox_move_line_up(_str commandline=”1”) name_info(‘,’) { int n = (int) commandline; int i; int orig_col = p_col; if (_select_type() == ‘CHAR’) { message(“selection changed”); wrox_to_line_selection(); } if (_select_type() == “LINE”) { begin_select(); cursor_up(n + 1); move_to_cursor(); } else { _str line; get_line(line); _delete_line(); cursor_up(n + 1); insert_line(line); } p_col = orig_col; // restore column position } _command void wrox_move_line_down(_str commandline=”1”) { int n = (int) commandline; int i; int orig_col = p_col; if (_select_type() == ‘CHAR’) { message(“selection changed”); wrox_to_line_selection(); } if (_select_type() == “LINE”) { end_select(); cursor_down(n); move_to_cursor(); } else { _str line; get_line(line); _delete_line(); cursor_down(n - 1); insert_line(line);
The commands work very similarly. First they test to see if there is a character selection. If there is, they convert it to a line selection. Then there are two cases, one for a line selection and the other to work with the current line. In each case, there is logic to move the cursor to the appropriate new location and move the line(s) there. The commands each take an optional number argument, which can be used to say how far to move the lines. The default is to move only one line up or down. You can bind the commands to keys for convenient use. The keys Alt+Up and Alt+Down are bound to prev-paragraph and next-paragraph in the CUA emulation. If you prefer, you can use those keys for wrox-move-line-up and wrox-move-line-down: defeventtab default_keys; def ‘A-Up’=wrox_move_line_up; def ‘A-Down’=wrox_move_line_down;
Alternatively, select some key combinations that are not already used.
Example: Callback Traces The code in this example requires code in wrox_list_files.e and wrox_hashes.e to be loaded. Above in the chapter, we covered SlickEdit callbacks and showed how you could add trace callbacks to understand when callbacks are called. The trace callbacks followed a simple pattern: void _switchbuf__trace() { say(“_switchbuf_ called”); }
You can use a SlickEdit macro to generate this code for all SlickEdit macros by scanning the supplied macro source for callback invocations. First, define a function wrox_list_callbacks() like this: #define CALL_LIST_PATTERN ‘call_list\(([‘’“])(\:v)\1’ STRARRAY wrox_list_callbacks() { _str macro_filespec = maybe_quote_filename(get_env(“VSLICKMACROS”)“*.e”); // NOTE: on Mac OS X VSLICKMACROS may not include a trailing slash ... (!) _str files[] = wrox_list_files(“+P -D “macro_filespec); int i; _str callbacks:[]; for (i = 0; i < files._length(); i++) { _str filename = files[i]; int temp_view_id; int orig_view_id = _create_temp_view(temp_view_id); get(filename); // loads file contents into temp buffer top(); int status = search(CALL_LIST_PATTERN, “U@>”); while (!status) { _str callback = get_text(match_length(“2”), match_length(“S2”));
353
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 354
Part III: Advanced SlickEdit callbacks:[callback] = 1; status = search(CALL_LIST_PATTERN, “U@>”); } _delete_temp_view(temp_view_id); activate_window(orig_view_id); } return wrox_hash_keys(callbacks); }
The function first lists all macro source files into an array, using the wrox_list_files() function from above in this chapter. Then, it loads a copy of each macro source file into a temporary buffer created by the _create_temp_view() function. The real work is in the loop, which uses a simple regular expression to search for each invocation of call_list(). For each invocation, the function adds the prefix pattern [the first argument to call_list()] to the set stored in the callbacks hash table. After the loop, the function returns the keys of the callbacks hash table. The result of the function is an array with all the callback event names. With this function in place, you can proceed to define a couple of commands to generate the trace functions: _command void wrox_make_callback_trace(_str callback=”“) name_info(‘,’VSARG2_REQUIRES_EDITORCTL) { insert_line(“void “callback”_trace() {“); insert_line(“ say(\“”callback” called\“);”); insert_line(“}“); insert_line(“”); } _command void wrox_foreach_callback(_str command=”“) name_info(COMMAND_ARG’,’VSARG2_REQUIRES_EDITORCTL) { command = prompt(command, “Command”); _str callbacks[] = wrox_list_callbacks(); int i; for (i = 0; i < callbacks._length(); i++) { execute(command” “callbacks[i]); } }
To generate macro source for callback trace functions using this code:
1. 2.
Open a new empty buffer. Invoke this command on the command line:
wrox-foreach-callback wrox-make-callback-trace
The wrox-foreach-callback command obtains the list of callbacks using the wrox_list_callbacks() function, then invokes the given command for each callback event. The wrox-make-callback-trace command prints out a simple trace function like that shown above for each callback event. You can easily modify the wrox-make-callback-trace command to customize the trace function generated. For example, you could have the trace function print the arguments passed to the callback. The ideas in this set of macros can be easily extended to very specific searches and edits over your own code base. This can be a great way to automate some large sets of simple changes.
354
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 355
Chapter 16: Slick-C Macro Programming
Example: WROX Function Names The code in this example requires code in wrox_list_files.e to be loaded. Throughout this book, all the example macros have been contained in files with names beginning with wrox_. The command and function names themselves (and even the global variables) also begin with wrox_. This has been done to ensure that there is no clash with supplied Slick-C macro names. As
explained above, if you inadvertently load a macro file named the same as an existing Slick-C module, or containing definitions with the same name as existing commands or functions, you can alter SlickEdit functionality in ways you did not intend. However, it is not particularly convenient to have a large number of commands beginning with wrox_. The advantage is that you know where the commands came from (and whom to blame if they don’t work). The disadvantages are that the commands are unnecessarily long to type, and auto-complete is not as effective. If you decide to incorporate some or all of the commands presented in this book into your own installation of SlickEdit, you may wish to consider dropping the wrox_ prefix, in order to make the commands easier to use. Of course, you wouldn’t want to have to edit all the source files by hand to do this. Also, you need to be careful that none of the shortened command names actually do conflict with supplied SlickEdit definitions. The macro in this section can automate this conversion task: #define WROX_FUNCTION_NAME ‘wrox_(\:v)\(‘ #define WROX_DEF ‘def (.*)= *wrox_(\:v);’ #define WROX_TYPES (PROC_TYPE | VAR_TYPE | COMMAND_TYPE) _command void wrox_convert_wrox_names(_str path = “”) name_info(DIR_ARG’,’VSARG2_REQUIRES_EDITORCTL) { path = prompt(path, “Path to WROX source files”); push_bookmark(); insert_line(‘#include “slick.sh”‘); _str macro_filespec = path”/*.e”; _str files[] = wrox_list_files(“+P +T -D “macro_filespec); int i; int file_count = 0; for (i = 0; i < files._length(); i++) { _str filename = files[i]; if (pos(“wrox_try”, filename) > 0) { continue; // skip wrox_try files: they’re for testing/demo purposes only } int temp_view_id; int orig_view_id = _create_temp_view(temp_view_id); get(filename); // loads file contents into temp buffer top(); if (!search(“defmain”)) { // skip Slick-C batch macro files pop_bookmark(); _delete_temp_view(temp_view_id); continue; } file_count++; int status = search(WROX_FUNCTION_NAME, “U@>”); while (!status) {
355
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 356
Part III: Advanced SlickEdit _str short_name = get_text(match_length(“1”), match_length(“S1”)); if (find_index(short_name, WROX_TYPES)) { // check whether short name already in use message(short_name “ (“filename”) already exists!”); pop_bookmark(); return; } status = search(WROX_FUNCTION_NAME, “U@>”); } // if we get here all names in the file are OK top(); deselect(); search(‘#include ‘); // skip down to first #include line search(‘$[ \t]*^’, ‘U>’); // skip down to following blank line select_line(); // start mark here bottom(); select_line(); // mark to rest of file activate_window(orig_view_id); bottom(); push_bookmark(); copy_to_cursor(); // copy/append data into this file deselect(); replace(WROX_FUNCTION_NAME, ‘\1(‘, “U*>”); // remove wrox_ from function names pop_bookmark(); replace(WROX_DEF, ‘def \1=\2;’, “U*>”); // remove wrox_ from keyboard defs insert_line(“”); _delete_temp_view(temp_view_id); } pop_bookmark(); message(“Files processed: “ file_count); }
The command takes a directory argument. It searches for .e files under that directory using the wrox_list_files() function. It skips any file containing a defmain(). These are Slick-C batch macros and are not to be converted. For each of the remaining files, it first checks that it is OK to remove the wrox_ prefix from all of the commands and functions having the prefix. It’s OK to remove the prefix only if no command or function already exists with the shortened name: We don’t want to redefine any pre-existing commands or functions. If any name clash is found, the macro aborts with a message about the name clash. If there are no name clashes, the macro appends the definitions from the source file into the current buffer. It then uses replace() to change the command and function names in definitions, invocations, and key bindings. Once the macro is complete, the current buffer should have all the WROX command and function definitions and key bindings from the selected directory. You should be able to load the file and have all the commands available with shorter names. Be careful about doing this. At the time of writing, all of the wrox_ commands and functions do not clash with SlickEdit commands and functions. However, in any new release or update, SlickEdit may add or rename commands or functions, creating a clash. The approach outlined here is inherently risky because the checks for name clashes occur only when you generate the new macro source file, not when you load it. If you want to be safe, you should retain some kind of namespace convention to avoid clashes.
356
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 357
Chapter 16: Slick-C Macro Programming
Example: N-Queens The final example is not practical, but I couldn’t resist throwing it in. Now you can solve the N-queens problem right in your editor. Simply load the code below (from the CD-ROM), open an empty buffer, type wrox-queens n, and press Enter. Don’t try this with n too big, or you will need Ctrl+Alt+Shift+F2! I did it with n up to 22. In case you are curious about the performance of Slick-C, it turns out that it runs just a little slower than Perl, which is among the fastest of the dynamic scripting languages. static static static static
int q_pos[]; boolean q_col[]; boolean q_diag1[]; boolean q_diag2[];
void wrox_queens_init(int size) { q_pos._makeempty(); q_col._makeempty(); q_diag1._makeempty(); q_diag2._makeempty(); int i; for (i = 0; i < size; i++) { q_pos[i] = -1; q_col[i] = false; } for (i = 0; i < 2 * size + 1; i++) { q_diag1[i] = false; q_diag2[i] = false; } } int wrox_queens_size() { return q_pos._length(); } int wrox_queens_col(int row) { return q_pos[row]; } void wrox_queens_place(int row, int col) { q_pos[row] = col; q_col[col] = true; int size = wrox_queens_size(); q_diag1[col - row + size] = true; q_diag2[col + row] = true; } int wrox_queens_unplace(int row) { int col = q_pos[row]; q_pos[row] = -1; q_col[col] = false; int size = wrox_queens_size(); q_diag1[col - row + size] = false; q_diag2[col + row] = false; return col;
357
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 358
Part III: Advanced SlickEdit } boolean wrox_queens_ok(int row, int col) { int size = wrox_queens_size(); return !(q_col[col] || q_diag1[col - row + size] || q_diag2[col + row]); } boolean wrox_queens_solve() { int row = 0; int col = 0; int size = wrox_queens_size(); while (row >= 0 && row < size) { while (col < size && !wrox_queens_ok(row, col)) { col++; } if (col < size) { wrox_queens_place(row, col); row++; col = 0; } else { row--; if (row >= 0) { col = wrox_queens_unplace(row) + 1; } } } return row == size; } void wrox_queens_print() { int size = wrox_queens_size(); int i; for (i = 0; i < size; i++) { insert_line(wrox_rightstr(“*“, wrox_queens_col(i) + 1)); } } _command void wrox_queens(int size=4) name_info(‘,’VSARG2_REQUIRES_EDITORCTL) { wrox_queens_init(size); int start_time = (int) _time(“B”); if (wrox_queens_solve()) { int end_time = (int) _time(“B”); wrox_queens_print(); int elapsed_seconds = (end_time - start_time) / 1000; message(“Board size “size” solved, took “elapsed_seconds” seconds.”); } else { message(“Board size “size” not solved.”); } }
358
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 359
Chapter 16: Slick-C Macro Programming
Summar y This chapter was long, and could have been a lot longer. There are several features we haven’t mentioned. For example, Slick-C has C-style pointers, but they aren’t covered in this book. I find that they are not necessary for most user macros. We also don’t cover GUI programming with Slick-C. We look at it briefly in the next chapter, but not in great detail. In my experience, users of SlickEdit use Slick-C to get a job done and are not generally too interested in spending time on a fancy interface. On the other hand, the SlickEdit team does use pointers, and GUI programming, in creating SlickEdit features. You can find out anything you need to know about SlickEdit by reading the supplied macro source. The supplied macro source contains about 750,000 lines of code, and many people write to the Community Forums to ask how it all works. Of course, there is no way to distill the entire 750,000 lines into an easy guide. There is a lot to say about Slick-C. The main aim of this chapter has been to give you an introduction to some of its most useful features, some of the common ways to get things done, and get you started writing your own macros. I hope this chapter has provided enough material to give you a useful start. I encourage you to read the supplied source to learn more. (Just don’t try to read it all at once.) Join the Community Forums too. Ask questions. Share your macros and ideas.
359
22150c16.qxd:WroxPro
9/25/07
1:44 AM
Page 360
22150c17.qxd:WroxPro
9/25/07
1:47 AM
Page 361
Customization Throughout this book, a major theme has been to show you many ways in which you can customize and extend SlickEdit for your own needs and preferences. In the previous chapter, we went into detail about Slick-C, which is the main power tool for customization in SlickEdit. In this chapter, we continue the theme of customization. We’ll look at how you can fine-tune the behavior of common keyboard commands by creating your own wrapper versions for them. This is easy to do and provides an effective way in many cases of getting the editor to behave just the way you want it to. SlickEdit supports a large number of programming languages out of the box, but new languages seem to appear just about every day. There are programming languages not supported by SlickEdit, from the ancient and obscure to some of the latest cutting-edge open-source languages. We’ll see how you can get a certain amount of support for these languages nevertheless, using SlickEdit’s features for defining new modes and lexers. In the previous chapter, we looked at several ways to use Slick-C to automate tasks in the editor and to create new features of your own. You may be surprised to learn that the capabilities of Slick-C are not limited to traditional programming, but also cover GUI programming. You can customize most of SlickEdit’s user interface, that is, forms and menus, using GUI tools provided in the editor. You can also create your own GUI elements for use with SlickEdit using these tools, or directly in code. We’ll take a look at a couple of relatively simple but useful examples of editing forms and working with menus. Finally, to be a truly expert user of SlickEdit, you need to be able to take control of your configuration. That means controlling it in code, so that your configuration settings are intentional and repeatable. All SlickEdit configuration settings can be accessed and controlled from Slick-C. We’ll cover several examples and show how you can determine the Slick-C code required for specific configuration changes you want to make.
22150c17.qxd:WroxPro
9/25/07
1:47 AM
Page 362
Part III: Advanced SlickEdit
Keyboard Customization Sometimes the standard behavior of SlickEdit keys is not what you want. Most of the time, various behaviors are available, such as those for Enter, Delete, and other keys, as discussed in Chapter 2. Occasionally, you may find you want completely different behavior from what SlickEdit provides. In this case, you can write your own macros and replace the SlickEdit commands bound to the keys. We saw an example of this in Chapter 6, where we replaced SlickEdit’s prev-word and next-word commands with wrox-prev-whitespace-word and wrox-next-whitespace-word, bound to Ctrl+Left and Ctrl+Right. Other times, the behavior for a key may be almost what you want, but not quite. In these cases, you can study the supplied source for the command bound to the key, to see whether configuration options are available. If you don’t find a suitable configuration option, you may opt to write your own version of the command. A good approach to this can be to write a wrapper command that delegates to the original command but provides additional behavior.
Example: Page-Down For example, you may have noticed that when you press Page-Down and reach the bottom of the file, you can sometimes end up with only a few lines of the buffer on screen, the bottom line of the buffer being partway up the window. In this situation, you might like Page-Down to realign the buffer in the window so that the bottom line of the buffer is at the bottom of the window. Realizing that the line-to-bottom command effectively does this very realignment, you might write a replacement page-down command: _command void wrox_page_down_realign() name_info(‘,’VSARG2_REQUIRES_EDITORCTL|VSARG2_READ_ONLY) { if (p_line != p_Noflines) { page_down(); } else { line_to_bottom(); } }
You can bind this command to Page-Down by including these lines in the macro file when you load it: defeventtab default_keys; def ‘PGDN’=wrox_page_down_realign;
This will get the command working in ordinary buffers. Recall from Chapter 13 that some modes of SlickEdit require special attention for user-defined commands on standard keys. Because Page-Down is a commonly used key in DIFFzilla, you will need to modify diffedit.e as explained in that chapter, to include wrox-page-down-realign as a supported command.
Example: Joining Lines The WROX emulation binds the useful command join-line to Alt+J. The join-line command has special handling for comments, to remove delimiters so that they flow correctly after joining lines. For ordinary lines, the behavior is simpler. It removes any leading spaces from the line below and joins it to
362
22150c17.qxd:WroxPro
9/25/07
1:47 AM
Page 363
Chapter 17: Customization the current line. If the cursor is at or beyond the end of the current line, the line is joined at the cursor position. Otherwise, it is joined at the end of the current line. I find I often use join-line with data or text files, and in this case when I join lines, I need to make sure the contents of the two lines are still separated by white space. To do this with the original join-line, I need to move the cursor to one character after the end of the first line before invoking join-line. Needless to say, this is inconvenient. A better solution is to write a wrapper for join-line: _command void wrox_join_line_with_space() name_info(‘,’VSARG2_REQUIRES_EDITORCTL) { push_bookmark(); int orig_col = p_col; end_line(); if (p_col > orig_col) { cursor_right(); } else { p_col = orig_col; } join_line(); pop_bookmark(); }
You can bind this command to Alt+J by including these lines in the macro file when it is loaded: defeventtab default_keys; def ‘A-J’=wrox_join_line_with_space;
Example: Tabbing Behavior In this example, we’ll change the behavior of Tab and Shift+Tab. The normal behavior of the Tab key in SlickEdit depends on the file type, the position of the cursor, and user extension settings. Generally, when editing code, if the cursor is in the beginning part of the line (before the first non-whitespace), the Tab key indents the line according to syntax rules. When the cursor is not in the leading whitespace, or for files that are not source code, the Tab key adds space or tabs up to the next tab stop. Rather than following arbitrary tab stops, I find a more useful behavior for the Tab (and Shift+Tab) keys is to follow the positions of items in the line above. That is, the Tab key moves the cursor under the next non-whitespace character on the line above, and the Shift+Tab key moves the cursor under the character after the previous whitespace character on the line above. This works well for typing data into columns, or even code where you have some items, for example, array initializations, lined up in columns. Another example is when you have line comments starting in the same column on several adjacent lines. Having Tab and Back-Tab configured to follow the fields above makes it very quick to jump to the correct column for the next line comment. The example macros below show how to achieve this. These macros are not intended for text files using real tab characters. For such files, the relationship between column positions on one line and another is complicated and depends on tab settings. _command void wrox_tab_matchtabs() { if (p_line < 2) { // no line above ctab();
363
22150c17.qxd:WroxPro
9/25/07
1:47 AM
Page 364
Part III: Advanced SlickEdit return; } cursor_up(); _str line_above; get_line(line_above); cursor_down(); _str remainder_above = strip(substr(line_above, p_col), ‘T’); if (length(remainder_above)