From 7ab66a1e430961da389b3e2898f2958e2f423d42 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Sun, 6 Apr 2008 00:04:09 +0000 Subject: [PATCH 01/56] * dired-aux.el (dired-overwrite-confirmed): Supply initial value. --- lisp/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 00e51eb43ed..321937d0362 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,7 @@ +2008-04-06 Chong Yidong + + * dired-aux.el (dired-overwrite-confirmed): Supply initial value. + 2008-04-04 Stephen Berman * newcomment.el (comment-enter-backward): Be careful to restore From 305492bbea813b2a39af835598f3310d0ee1e942 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Sun, 6 Apr 2008 00:04:52 +0000 Subject: [PATCH 02/56] (dired-overwrite-confirmed): Supply initial value. --- lisp/dired-aux.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index 8908e5ba425..d7d1d607999 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -1129,7 +1129,7 @@ Special value `always' suppresses confirmation." (other :tag "ask" t)) :group 'dired) -(defvar dired-overwrite-confirmed) +(defvar dired-overwrite-confirmed nil) (defun dired-handle-overwrite (to) ;; Save old version of file TO that is to be overwritten. From ba695106b417f95931b85f8103dd02f7849cdccd Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:54:44 +0000 Subject: [PATCH 03/56] New file. --- src/mactoolbox.c | 6208 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 6208 insertions(+) create mode 100644 src/mactoolbox.c diff --git a/src/mactoolbox.c b/src/mactoolbox.c new file mode 100644 index 00000000000..e1fa79ac8be --- /dev/null +++ b/src/mactoolbox.c @@ -0,0 +1,6208 @@ +/* Functions for GUI implemented with (HI)Toolbox on the Mac OS. + Copyright (C) 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include + +#include + +#include "lisp.h" +#include "blockinput.h" + +#include "macterm.h" + +#if !TARGET_API_MAC_CARBON +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined (__MRC__) || (__MSL__ >= 0x6000) +#include +#endif + +#if __profile__ +#include +#endif +#endif /* not TARGET_API_MAC_CARBON */ + +#include "charset.h" +#include "coding.h" +#include "frame.h" +#include "dispextern.h" +#include "fontset.h" +#include "termhooks.h" +#include "buffer.h" +#include "window.h" +#include "keyboard.h" + +#include + +#ifndef MAC_OSX +#include +#endif + + +/************************************************************************ + General + ************************************************************************/ + +/* The difference in pixels between the top left corner of the + Emacs window (including possible window manager decorations) + and FRAME_MAC_WINDOW (f). */ +#define FRAME_OUTER_TO_INNER_DIFF_X(f) ((f)->x_pixels_diff) +#define FRAME_OUTER_TO_INNER_DIFF_Y(f) ((f)->y_pixels_diff) + +#define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP) + +void +mac_alert_sound_play () +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 + AlertSoundPlay (); +#else + SysBeep (1); +#endif +} + + +/************************************************************************ + Application + ************************************************************************/ + +extern struct frame *mac_focus_frame P_ ((struct mac_display_info *)); +extern void do_keystroke P_ ((EventKind, unsigned char, UInt32, UInt32, + unsigned long, struct input_event *)); +extern UInt32 mac_mapped_modifiers P_ ((UInt32, UInt32)); +#if TARGET_API_MAC_CARBON +extern int mac_to_emacs_modifiers P_ ((UInt32, UInt32)); +#else +extern int mac_to_emacs_modifiers P_ ((EventModifiers, EventModifiers)); +#endif + +#if TARGET_API_MAC_CARBON +/* Points to the variable `inev' in the function XTread_socket. It is + used for passing an input event to the function back from + Carbon/Apple event handlers. */ +static struct input_event *read_socket_inev = NULL; + +extern const unsigned char keycode_to_xkeysym_table[]; +extern EMACS_INT extra_keyboard_modifiers; + +extern Lisp_Object Qhi_command; +#if USE_MAC_TSM +static TSMDocumentID tsm_document_id; +extern Lisp_Object Qtext_input; +extern Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event; +extern Lisp_Object Vmac_ts_active_input_overlay; +extern Lisp_Object Qbefore_string; +extern Lisp_Object Vmac_ts_script_language_on_focus; +extern Lisp_Object saved_ts_script_language_on_focus; +#endif + +static int mac_event_to_emacs_modifiers P_ ((EventRef)); +static OSStatus install_menu_target_item_handler P_ ((void)); +#ifdef MAC_OSX +static OSStatus install_service_handler P_ ((void)); +#endif + +extern OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID, + Lisp_Object, + Lisp_Object, + EventRef, UInt32, + const EventParamName *, + const EventParamType *)); + +#if USE_MAC_TSM +extern OSStatus mac_restore_keyboard_input_source P_ ((void)); +extern void mac_save_keyboard_input_source P_ ((void)); + +static OSStatus +mac_tsm_resume () +{ + OSStatus err; + + err = ActivateTSMDocument (tsm_document_id); + if (err == noErr) + err = mac_restore_keyboard_input_source (); + + return err; +} + +static OSStatus +mac_tsm_suspend () +{ + OSStatus err; + + mac_save_keyboard_input_source (); + err = DeactivateTSMDocument (tsm_document_id); + + return err; +} + +static void +init_tsm () +{ +#ifdef MAC_OSX + static InterfaceTypeList types = {kUnicodeDocument}; +#else + static InterfaceTypeList types = {kTextService}; +#endif + + NewTSMDocument (sizeof (types) / sizeof (types[0]), types, + &tsm_document_id, 0); +} +#endif /* USE_MAC_TSM */ + +static pascal OSStatus +mac_handle_keyboard_event (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + OSStatus err, result = eventNotHandledErr; + UInt32 event_kind, key_code, modifiers; + unsigned char char_code; + + event_kind = GetEventKind (event); + switch (event_kind) + { + case kEventRawKeyDown: + case kEventRawKeyRepeat: + case kEventRawKeyUp: + /* When using Carbon Events, we need to pass raw keyboard events + to the TSM ourselves. If TSM handles it, it will pass back + noErr, otherwise it will pass back "eventNotHandledErr" and + we can process it normally. */ + result = CallNextEventHandler (next_handler, event); + if (result != eventNotHandledErr) + break; + + if (read_socket_inev == NULL) + break; + +#if USE_MAC_TSM + if (read_socket_inev->kind != NO_EVENT) + { + result = noErr; + break; + } +#endif + + if (event_kind == kEventRawKeyUp) + break; + + err = GetEventParameter (event, kEventParamKeyMacCharCodes, + typeChar, NULL, + sizeof (char), NULL, &char_code); + if (err != noErr) + break; + + err = GetEventParameter (event, kEventParamKeyCode, + typeUInt32, NULL, + sizeof (UInt32), NULL, &key_code); + if (err != noErr) + break; + + err = GetEventParameter (event, kEventParamKeyModifiers, + typeUInt32, NULL, + sizeof (UInt32), NULL, &modifiers); + if (err != noErr) + break; + + do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey), + char_code, key_code, modifiers, + ((unsigned long) + (GetEventTime (event) / kEventDurationMillisecond)), + read_socket_inev); + result = noErr; + break; + + default: + abort (); + } + + return result; +} + +static pascal OSStatus +mac_handle_command_event (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + OSStatus err, result = eventNotHandledErr; + HICommand command; + static const EventParamName names[] = + {kEventParamDirectObject, kEventParamKeyModifiers}; + static const EventParamType types[] = + {typeHICommand, typeUInt32}; + int num_params = sizeof (names) / sizeof (names[0]); + + err = GetEventParameter (event, kEventParamDirectObject, typeHICommand, + NULL, sizeof (HICommand), NULL, &command); + if (err != noErr) + return eventNotHandledErr; + + switch (GetEventKind (event)) + { + case kEventCommandProcess: + result = CallNextEventHandler (next_handler, event); + if (result != eventNotHandledErr) + break; + + err = GetEventParameter (event, kEventParamDirectObject, + typeHICommand, NULL, + sizeof (HICommand), NULL, &command); + + if (err != noErr || command.commandID == 0) + break; + + /* A HI command event is mapped to an Apple event whose event + class symbol is `hi-command' and event ID is its command + ID. */ + err = mac_store_event_ref_as_apple_event (0, command.commandID, + Qhi_command, Qnil, + event, num_params, + names, types); + if (err == noErr) + result = noErr; + break; + + default: + abort (); + } + + return result; +} + +static pascal OSStatus +mac_handle_mouse_event (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + OSStatus err, result = eventNotHandledErr; + + switch (GetEventKind (event)) + { + case kEventMouseWheelMoved: + { + WindowRef wp; + struct frame *f; + EventMouseWheelAxis axis; + SInt32 delta; + Point point; + + result = CallNextEventHandler (next_handler, event); + if (result != eventNotHandledErr || read_socket_inev == NULL) + break; + + f = mac_focus_frame (&one_mac_display_info); + + err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef, + NULL, sizeof (WindowRef), NULL, &wp); + if (err != noErr + || wp != FRAME_MAC_WINDOW (f)) + break; + + err = GetEventParameter (event, kEventParamMouseWheelAxis, + typeMouseWheelAxis, NULL, + sizeof (EventMouseWheelAxis), NULL, &axis); + if (err != noErr || axis != kEventMouseWheelAxisY) + break; + + err = GetEventParameter (event, kEventParamMouseLocation, + typeQDPoint, NULL, sizeof (Point), + NULL, &point); + if (err != noErr) + break; + + point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); + point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); + if (point.h < 0 || point.v < 0 + || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1), + f->tool_bar_window)) + break; + + err = GetEventParameter (event, kEventParamMouseWheelDelta, + typeSInt32, NULL, sizeof (SInt32), + NULL, &delta); + if (err != noErr) + break; + + read_socket_inev->kind = WHEEL_EVENT; + read_socket_inev->code = 0; + read_socket_inev->modifiers = + (mac_event_to_emacs_modifiers (event) + | ((delta < 0) ? down_modifier : up_modifier)); + XSETINT (read_socket_inev->x, point.h); + XSETINT (read_socket_inev->y, point.v); + XSETFRAME (read_socket_inev->frame_or_window, f); + + result = noErr; + } + break; + + default: + abort (); + } + + return result; +} + +#if USE_MAC_TSM +static pascal OSStatus +mac_handle_text_input_event (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + OSStatus err, result; + Lisp_Object id_key = Qnil; + int num_params; + const EventParamName *names; + const EventParamType *types; + static UInt32 seqno_uaia = 0; + static const EventParamName names_uaia[] = + {kEventParamTextInputSendComponentInstance, + kEventParamTextInputSendRefCon, + kEventParamTextInputSendSLRec, + kEventParamTextInputSendFixLen, + kEventParamTextInputSendText, + kEventParamTextInputSendUpdateRng, + kEventParamTextInputSendHiliteRng, + kEventParamTextInputSendClauseRng, + kEventParamTextInputSendPinRng, + kEventParamTextInputSendTextServiceEncoding, + kEventParamTextInputSendTextServiceMacEncoding, + EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER}; + static const EventParamType types_uaia[] = + {typeComponentInstance, + typeLongInteger, + typeIntlWritingCode, + typeLongInteger, +#ifdef MAC_OSX + typeUnicodeText, +#else + typeChar, +#endif + typeTextRangeArray, + typeTextRangeArray, + typeOffsetArray, + typeTextRange, + typeUInt32, + typeUInt32, + typeUInt32}; + static const EventParamName names_ufke[] = + {kEventParamTextInputSendComponentInstance, + kEventParamTextInputSendRefCon, + kEventParamTextInputSendSLRec, + kEventParamTextInputSendText}; + static const EventParamType types_ufke[] = + {typeComponentInstance, + typeLongInteger, + typeIntlWritingCode, + typeUnicodeText}; + + result = CallNextEventHandler (next_handler, event); + if (result != eventNotHandledErr) + return result; + + switch (GetEventKind (event)) + { + case kEventTextInputUpdateActiveInputArea: + id_key = Qupdate_active_input_area; + num_params = sizeof (names_uaia) / sizeof (names_uaia[0]); + names = names_uaia; + types = types_uaia; + SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER, + typeUInt32, sizeof (UInt32), &seqno_uaia); + seqno_uaia++; + result = noErr; + break; + + case kEventTextInputUnicodeForKeyEvent: + { + EventRef kbd_event; + UInt32 actual_size, modifiers, key_code; + + err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent, + typeEventRef, NULL, sizeof (EventRef), NULL, + &kbd_event); + if (err == noErr) + err = GetEventParameter (kbd_event, kEventParamKeyModifiers, + typeUInt32, NULL, + sizeof (UInt32), NULL, &modifiers); + if (err == noErr) + err = GetEventParameter (kbd_event, kEventParamKeyCode, + typeUInt32, NULL, sizeof (UInt32), + NULL, &key_code); + if (err == noErr && mac_mapped_modifiers (modifiers, key_code)) + /* There're mapped modifier keys. Process it in + do_keystroke. */ + break; + if (err == noErr) + err = GetEventParameter (kbd_event, kEventParamKeyUnicodes, + typeUnicodeText, NULL, 0, &actual_size, + NULL); + if (err == noErr && actual_size == sizeof (UniChar)) + { + UniChar code; + + err = GetEventParameter (kbd_event, kEventParamKeyUnicodes, + typeUnicodeText, NULL, + sizeof (UniChar), NULL, &code); + if (err == noErr && code < 0x80) + { + /* ASCII character. Process it in do_keystroke. */ + if (read_socket_inev && code >= 0x20 && code <= 0x7e + && !(key_code <= 0x7f + && keycode_to_xkeysym_table [key_code])) + { + struct frame *f = mac_focus_frame (&one_mac_display_info); + + read_socket_inev->kind = ASCII_KEYSTROKE_EVENT; + read_socket_inev->code = code; + read_socket_inev->modifiers = + mac_to_emacs_modifiers (modifiers, 0); + read_socket_inev->modifiers |= + (extra_keyboard_modifiers + & (meta_modifier | alt_modifier + | hyper_modifier | super_modifier)); + XSETFRAME (read_socket_inev->frame_or_window, f); + } + break; + } + } + if (err == noErr) + { + /* Non-ASCII keystrokes without mapped modifiers are + processed at the Lisp level. */ + id_key = Qunicode_for_key_event; + num_params = sizeof (names_ufke) / sizeof (names_ufke[0]); + names = names_ufke; + types = types_ufke; + result = noErr; + } + } + break; + + case kEventTextInputOffsetToPos: + { + struct frame *f; + struct window *w; + Point p; + + if (!OVERLAYP (Vmac_ts_active_input_overlay)) + break; + + /* Strictly speaking, this is not always correct because + previous events may change some states about display. */ + if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string))) + { + /* Active input area is displayed around the current point. */ + f = SELECTED_FRAME (); + w = XWINDOW (f->selected_window); + } + else if (WINDOWP (echo_area_window)) + { + /* Active input area is displayed in the echo area. */ + w = XWINDOW (echo_area_window); + f = WINDOW_XFRAME (w); + } + else + break; + + p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x) + + WINDOW_LEFT_FRINGE_WIDTH (w) + + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f)); + p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y) + + FONT_BASE (FRAME_FONT (f)) + + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f)); + err = SetEventParameter (event, kEventParamTextInputReplyPoint, + typeQDPoint, sizeof (typeQDPoint), &p); + if (err == noErr) + result = noErr; + } + break; + + default: + abort (); + } + + if (!NILP (id_key)) + err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key, + event, num_params, + names, types); + return result; +} +#endif + +OSStatus +install_application_handler () +{ + OSStatus err = noErr; + + if (err == noErr) + { + static const EventTypeSpec specs[] = + {{kEventClassKeyboard, kEventRawKeyDown}, + {kEventClassKeyboard, kEventRawKeyRepeat}, + {kEventClassKeyboard, kEventRawKeyUp}}; + + err = InstallApplicationEventHandler (NewEventHandlerUPP + (mac_handle_keyboard_event), + GetEventTypeCount (specs), + specs, NULL, NULL); + } + + if (err == noErr) + { + static const EventTypeSpec specs[] = + {{kEventClassCommand, kEventCommandProcess}}; + + err = InstallApplicationEventHandler (NewEventHandlerUPP + (mac_handle_command_event), + GetEventTypeCount (specs), + specs, NULL, NULL); + } + + if (err == noErr) + { + static const EventTypeSpec specs[] = + {{kEventClassMouse, kEventMouseWheelMoved}}; + + err = InstallApplicationEventHandler (NewEventHandlerUPP + (mac_handle_mouse_event), + GetEventTypeCount (specs), + specs, NULL, NULL); + } + +#if USE_MAC_TSM + if (err == noErr) + { + static const EventTypeSpec spec[] = + {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea}, + {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent}, + {kEventClassTextInput, kEventTextInputOffsetToPos}}; + + err = InstallApplicationEventHandler (NewEventHandlerUPP + (mac_handle_text_input_event), + GetEventTypeCount (spec), + spec, NULL, NULL); + } +#endif + + if (err == noErr) + err = install_menu_target_item_handler (); + +#ifdef MAC_OSX + if (err == noErr) + err = install_service_handler (); +#endif + + return err; +} +#endif /* TARGET_API_MAC_CARBON */ + + +/************************************************************************ + Windows + ************************************************************************/ + +#define DEFAULT_NUM_COLS 80 + +#define MIN_DOC_SIZE 64 +#define MAX_DOC_SIZE 32767 + +/* Drag and Drop */ +static OSErr install_drag_handler P_ ((WindowRef)); +static void remove_drag_handler P_ ((WindowRef)); + +#if USE_CG_DRAWING +static void mac_prepare_for_quickdraw P_ ((struct frame *)); +#endif + +extern void mac_handle_visibility_change P_ ((struct frame *)); +extern void mac_handle_origin_change P_ ((struct frame *)); +extern void mac_handle_size_change P_ ((struct frame *, int, int)); + +#if TARGET_API_MAC_CARBON +#ifdef MAC_OSX +extern Lisp_Object Qwindow; +extern Lisp_Object Qtoolbar_switch_mode; +#endif +#endif + +static void +do_window_update (WindowRef win) +{ + struct frame *f = mac_window_to_frame (win); + + BeginUpdate (win); + + /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED + below. */ + if (win != tip_window) + { + if (f->async_visible == 0) + { + /* Update events may occur when a frame gets iconified. */ +#if 0 + f->async_visible = 1; + f->async_iconified = 0; + SET_FRAME_GARBAGED (f); +#endif + } + else + { + Rect r; +#if TARGET_API_MAC_CARBON + RgnHandle region = NewRgn (); + + GetPortVisibleRegion (GetWindowPort (win), region); + GetRegionBounds (region, &r); + expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top); +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (f); +#endif + UpdateControls (win, region); + DisposeRgn (region); +#else + r = (*win->visRgn)->rgnBBox; + expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top); + UpdateControls (win, win->visRgn); +#endif + } + } + + EndUpdate (win); +} + +static int +is_emacs_window (WindowRef win) +{ + Lisp_Object tail, frame; + + if (!win) + return 0; + + FOR_EACH_FRAME (tail, frame) + if (FRAME_MAC_P (XFRAME (frame))) + if (FRAME_MAC_WINDOW (XFRAME (frame)) == win) + return 1; + + return 0; +} + +/* Handle drags in size box. Based on code contributed by Ben + Mesander and IM - Window Manager A. */ + +static void +do_grow_window (w, e) + WindowRef w; + const EventRecord *e; +{ + Rect limit_rect; + int rows, columns, width, height; + struct frame *f = mac_window_to_frame (w); + XSizeHints *size_hints = FRAME_SIZE_HINTS (f); + int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE; +#if TARGET_API_MAC_CARBON + Rect new_rect; +#else + long grow_size; +#endif + + if (size_hints->flags & PMinSize) + { + min_width = size_hints->min_width; + min_height = size_hints->min_height; + } + SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE); + +#if TARGET_API_MAC_CARBON + if (!ResizeWindow (w, e->where, &limit_rect, &new_rect)) + return; + height = new_rect.bottom - new_rect.top; + width = new_rect.right - new_rect.left; +#else + grow_size = GrowWindow (w, e->where, &limit_rect); + /* see if it really changed size */ + if (grow_size == 0) + return; + height = HiWord (grow_size); + width = LoWord (grow_size); +#endif + + if (width != FRAME_PIXEL_WIDTH (f) + || height != FRAME_PIXEL_HEIGHT (f)) + { + rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); + columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); + + x_set_window_size (f, 0, columns, rows); + } +} + +#if TARGET_API_MAC_CARBON +static Point +mac_get_ideal_size (f) + struct frame *f; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + WindowRef w = FRAME_MAC_WINDOW (f); + Point ideal_size; + Rect standard_rect; + int height, width, columns, rows; + + ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS); + ideal_size.v = dpyinfo->height; + IsWindowInStandardState (w, &ideal_size, &standard_rect); + /* Adjust the standard size according to character boundaries. */ + width = standard_rect.right - standard_rect.left; + height = standard_rect.bottom - standard_rect.top; + columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); + rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); + ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns); + ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows); + + return ideal_size; +} + +static pascal OSStatus +mac_handle_window_event (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + WindowRef wp; + OSStatus err, result = eventNotHandledErr; + struct frame *f; + UInt32 attributes; + XSizeHints *size_hints; + + err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef, + NULL, sizeof (WindowRef), NULL, &wp); + if (err != noErr) + return eventNotHandledErr; + + f = mac_window_to_frame (wp); + switch (GetEventKind (event)) + { + /* -- window refresh events -- */ + + case kEventWindowUpdate: + result = CallNextEventHandler (next_handler, event); + if (result != eventNotHandledErr) + break; + + do_window_update (wp); + result = noErr; + break; + + /* -- window state change events -- */ + + case kEventWindowShowing: + size_hints = FRAME_SIZE_HINTS (f); + if (!(size_hints->flags & (USPosition | PPosition))) + { + struct frame *sf = SELECTED_FRAME (); + + if (!(FRAME_MAC_P (sf) && sf->async_visible)) + RepositionWindow (wp, NULL, kWindowCenterOnMainScreen); + else + { + RepositionWindow (wp, FRAME_MAC_WINDOW (sf), +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 + kWindowCascadeStartAtParentWindowScreen +#else + kWindowCascadeOnParentWindowScreen +#endif + ); +#if USE_MAC_TOOLBAR + /* This is a workaround. RepositionWindow fails to put + a window at the cascading position when its parent + window has a Carbon HIToolbar. */ + if ((f->left_pos == sf->left_pos + && f->top_pos == sf->top_pos) + || (f->left_pos == sf->left_pos + 10 * 2 + && f->top_pos == sf->top_pos + 32 * 2)) + MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32); +#endif + } + result = noErr; + } + break; + + case kEventWindowHiding: + /* Before unmapping the window, update the WM_SIZE_HINTS + property to claim that the current position of the window is + user-specified, rather than program-specified, so that when + the window is mapped again, it will be placed at the same + location, without forcing the user to position it by hand + again (they have already done that once for this window.) */ + x_wm_set_size_hint (f, (long) 0, 1); + result = noErr; + break; + + case kEventWindowShown: + case kEventWindowHidden: + case kEventWindowCollapsed: + case kEventWindowExpanded: + mac_handle_visibility_change (f); + result = noErr; + break; + + case kEventWindowBoundsChanging: + result = CallNextEventHandler (next_handler, event); + if (result != eventNotHandledErr) + break; + + err = GetEventParameter (event, kEventParamAttributes, typeUInt32, + NULL, sizeof (UInt32), NULL, &attributes); + if (err != noErr) + break; + + size_hints = FRAME_SIZE_HINTS (f); + if ((attributes & kWindowBoundsChangeUserResize) + && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize)) + == (PResizeInc | PBaseSize | PMinSize))) + { + Rect bounds; + int width, height; + + err = GetEventParameter (event, kEventParamCurrentBounds, + typeQDRectangle, NULL, sizeof (Rect), + NULL, &bounds); + if (err != noErr) + break; + + width = bounds.right - bounds.left; + height = bounds.bottom - bounds.top; + + if (width < size_hints->min_width) + width = size_hints->min_width; + else + width = size_hints->base_width + + (int) ((width - size_hints->base_width) + / (float) size_hints->width_inc + .5) + * size_hints->width_inc; + + if (height < size_hints->min_height) + height = size_hints->min_height; + else + height = size_hints->base_height + + (int) ((height - size_hints->base_height) + / (float) size_hints->height_inc + .5) + * size_hints->height_inc; + + bounds.right = bounds.left + width; + bounds.bottom = bounds.top + height; + SetEventParameter (event, kEventParamCurrentBounds, + typeQDRectangle, sizeof (Rect), &bounds); + result = noErr; + } + break; + + case kEventWindowBoundsChanged: + err = GetEventParameter (event, kEventParamAttributes, typeUInt32, + NULL, sizeof (UInt32), NULL, &attributes); + if (err != noErr) + break; + + if (attributes & kWindowBoundsChangeSizeChanged) + { + Rect bounds; + + err = GetEventParameter (event, kEventParamCurrentBounds, + typeQDRectangle, NULL, sizeof (Rect), + NULL, &bounds); + if (err == noErr) + { + int width, height; + + width = bounds.right - bounds.left; + height = bounds.bottom - bounds.top; + mac_handle_size_change (f, width, height); + mac_wakeup_from_rne (); + } + } + + if (attributes & kWindowBoundsChangeOriginChanged) + mac_handle_origin_change (f); + + result = noErr; + break; + + /* -- window action events -- */ + + case kEventWindowClose: + { + struct input_event buf; + + EVENT_INIT (buf); + buf.kind = DELETE_WINDOW_EVENT; + XSETFRAME (buf.frame_or_window, f); + buf.arg = Qnil; + kbd_buffer_store_event (&buf); + } + result = noErr; + break; + + case kEventWindowGetIdealSize: + result = CallNextEventHandler (next_handler, event); + if (result != eventNotHandledErr) + break; + + { + Point ideal_size = mac_get_ideal_size (f); + + err = SetEventParameter (event, kEventParamDimensions, + typeQDPoint, sizeof (Point), &ideal_size); + if (err == noErr) + result = noErr; + } + break; + +#ifdef MAC_OSX + case kEventWindowToolbarSwitchMode: + { + static const EventParamName names[] = {kEventParamDirectObject, + kEventParamWindowMouseLocation, + kEventParamKeyModifiers, + kEventParamMouseButton, + kEventParamClickCount, + kEventParamMouseChord}; + static const EventParamType types[] = {typeWindowRef, + typeQDPoint, + typeUInt32, + typeMouseButton, + typeUInt32, + typeUInt32}; + int num_params = sizeof (names) / sizeof (names[0]); + + err = mac_store_event_ref_as_apple_event (0, 0, + Qwindow, + Qtoolbar_switch_mode, + event, num_params, + names, types); + } + if (err == noErr) + result = noErr; + break; +#endif + +#if USE_MAC_TSM + /* -- window focus events -- */ + + case kEventWindowFocusAcquired: + err = mac_tsm_resume (); + if (err == noErr) + result = noErr; + break; + + case kEventWindowFocusRelinquish: + err = mac_tsm_suspend (); + if (err == noErr) + result = noErr; + break; +#endif + + default: + abort (); + } + + return result; +} +#endif + +/* Handle clicks in zoom box. Calculation of "standard state" based + on code in IM - Window Manager A and code contributed by Ben + Mesander. The standard state of an Emacs window is 80-characters + wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */ + +static void +do_zoom_window (WindowRef w, int zoom_in_or_out) +{ + Rect zoom_rect, port_rect; + int width, height; + struct frame *f = mac_window_to_frame (w); +#if TARGET_API_MAC_CARBON + Point ideal_size = mac_get_ideal_size (f); + + GetWindowBounds (w, kWindowContentRgn, &port_rect); + if (IsWindowInStandardState (w, &ideal_size, &zoom_rect) + && port_rect.left == zoom_rect.left + && port_rect.top == zoom_rect.top) + zoom_in_or_out = inZoomIn; + else + zoom_in_or_out = inZoomOut; + +#ifdef MAC_OS8 + mac_clear_area (f, 0, 0, port_rect.right - port_rect.left, + port_rect.bottom - port_rect.top); +#endif + ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size); +#else /* not TARGET_API_MAC_CARBON */ + GrafPtr save_port; + Point top_left; + int w_title_height, rows; + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + GetPort (&save_port); + + SetPortWindowPort (w); + + /* Clear window to avoid flicker. */ + EraseRect (&(w->portRect)); + if (zoom_in_or_out == inZoomOut) + { + SetPt (&top_left, w->portRect.left, w->portRect.top); + LocalToGlobal (&top_left); + + /* calculate height of window's title bar */ + w_title_height = top_left.v - 1 + - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight (); + + /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */ + zoom_rect = qd.screenBits.bounds; + zoom_rect.top += w_title_height; + InsetRect (&zoom_rect, 8, 4); /* not too tight */ + + zoom_rect.right = zoom_rect.left + + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS); + + /* Adjust the standard size according to character boundaries. */ + rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top); + zoom_rect.bottom = + zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows); + + (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState + = zoom_rect; + } + + ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo)); + + SetPort (save_port); +#endif /* not TARGET_API_MAC_CARBON */ + +#if !TARGET_API_MAC_CARBON + /* retrieve window size and update application values */ + port_rect = w->portRect; + height = port_rect.bottom - port_rect.top; + width = port_rect.right - port_rect.left; + + mac_handle_size_change (f, width, height); + mac_handle_origin_change (f); +#endif +} + +static OSStatus +install_window_handler (window) + WindowRef window; +{ + OSStatus err = noErr; + +#if TARGET_API_MAC_CARBON + if (err == noErr) + { + static const EventTypeSpec specs[] = + { + /* -- window refresh events -- */ + {kEventClassWindow, kEventWindowUpdate}, + /* -- window state change events -- */ + {kEventClassWindow, kEventWindowShowing}, + {kEventClassWindow, kEventWindowHiding}, + {kEventClassWindow, kEventWindowShown}, + {kEventClassWindow, kEventWindowHidden}, + {kEventClassWindow, kEventWindowCollapsed}, + {kEventClassWindow, kEventWindowExpanded}, + {kEventClassWindow, kEventWindowBoundsChanging}, + {kEventClassWindow, kEventWindowBoundsChanged}, + /* -- window action events -- */ + {kEventClassWindow, kEventWindowClose}, + {kEventClassWindow, kEventWindowGetIdealSize}, +#ifdef MAC_OSX + {kEventClassWindow, kEventWindowToolbarSwitchMode}, +#endif +#if USE_MAC_TSM + /* -- window focus events -- */ + {kEventClassWindow, kEventWindowFocusAcquired}, + {kEventClassWindow, kEventWindowFocusRelinquish}, +#endif + }; + static EventHandlerUPP handle_window_eventUPP = NULL; + + if (handle_window_eventUPP == NULL) + handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event); + + err = InstallWindowEventHandler (window, handle_window_eventUPP, + GetEventTypeCount (specs), + specs, NULL, NULL); + } +#endif + + if (err == noErr) + err = install_drag_handler (window); + + return err; +} + +static void +remove_window_handler (window) + WindowRef window; +{ + remove_drag_handler (window); +} + +void +mac_get_window_bounds (f, inner, outer) + struct frame *f; + Rect *inner, *outer; +{ +#if TARGET_API_MAC_CARBON + GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner); + GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer); +#else /* not TARGET_API_MAC_CARBON */ + RgnHandle region = NewRgn (); + + GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region); + *inner = (*region)->rgnBBox; + GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region); + *outer = (*region)->rgnBBox; + DisposeRgn (region); +#endif /* not TARGET_API_MAC_CARBON */ +} + +Rect * +mac_get_frame_bounds (f, r) + struct frame *f; + Rect *r; +{ +#if TARGET_API_MAC_CARBON + return GetWindowPortBounds (FRAME_MAC_WINDOW (f), r); +#else + *r = FRAME_MAC_WINDOW (f)->portRect; + + return r; +#endif +} + +void +mac_get_frame_mouse (f, point) + struct frame *f; + Point *point; +{ +#if TARGET_API_MAC_CARBON + GetGlobalMouse (point); + point->h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); + point->v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); +#else + SetPortWindowPort (FRAME_MAC_WINDOW (f)); + GetMouse (point); +#endif +} + +void +mac_convert_frame_point_to_global (f, x, y) + struct frame *f; + int *x, *y; +{ + *x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); + *y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); +} + +#if TARGET_API_MAC_CARBON +void +mac_update_proxy_icon (f) + struct frame *f; +{ + OSStatus err; + Lisp_Object file_name = + XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer)->filename; + Window w = FRAME_MAC_WINDOW (f); + AliasHandle alias = NULL; + + err = GetWindowProxyAlias (w, &alias); + if (err == errWindowDoesNotHaveProxy && !STRINGP (file_name)) + return; + + if (STRINGP (file_name)) + { + AEDesc desc; +#ifdef MAC_OSX + FSRef fref, fref_proxy; +#else + FSSpec fss, fss_proxy; +#endif + Boolean changed; + Lisp_Object encoded_file_name = ENCODE_FILE (file_name); + +#ifdef MAC_OSX + err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name), + SBYTES (encoded_file_name), typeFSRef, &desc); +#else + SetPortWindowPort (w); + err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name), + SBYTES (encoded_file_name), typeFSS, &desc); +#endif + if (err == noErr) + { +#ifdef MAC_OSX + err = AEGetDescData (&desc, &fref, sizeof (FSRef)); +#else + err = AEGetDescData (&desc, &fss, sizeof (FSSpec)); +#endif + AEDisposeDesc (&desc); + } + if (err == noErr) + { + if (alias) + { + /* (FS)ResolveAlias never sets `changed' to true if + `alias' is minimal. */ +#ifdef MAC_OSX + err = FSResolveAlias (NULL, alias, &fref_proxy, &changed); + if (err == noErr) + err = FSCompareFSRefs (&fref, &fref_proxy); +#else + err = ResolveAlias (NULL, alias, &fss_proxy, &changed); + if (err == noErr) + err = !(fss.vRefNum == fss_proxy.vRefNum + && fss.parID == fss_proxy.parID + && EqualString (fss.name, fss_proxy.name, + false, true)); +#endif + } + if (err != noErr || alias == NULL) + { + if (alias) + DisposeHandle ((Handle) alias); +#ifdef MAC_OSX + err = FSNewAliasMinimal (&fref, &alias); +#else + err = NewAliasMinimal (&fss, &alias); +#endif + changed = true; + } + } + if (err == noErr) + if (changed) + err = SetWindowProxyAlias (w, alias); + } + + if (alias) + DisposeHandle ((Handle) alias); + + if (err != noErr || !STRINGP (file_name)) + RemoveWindowProxy (w); +} +#endif + +/* Mac replacement for XSetWindowBackground. */ + +void +mac_set_frame_window_background (f, color) + struct frame *f; + unsigned long color; +{ + WindowRef w = FRAME_MAC_WINDOW (f); +#if !TARGET_API_MAC_CARBON + AuxWinHandle aw_handle; + CTabHandle ctab_handle; + ColorSpecPtr ct_table; + short ct_size; +#endif + RGBColor bg_color; + + bg_color.red = RED16_FROM_ULONG (color); + bg_color.green = GREEN16_FROM_ULONG (color); + bg_color.blue = BLUE16_FROM_ULONG (color); + +#if TARGET_API_MAC_CARBON + SetWindowContentColor (w, &bg_color); +#else + if (GetAuxWin (w, &aw_handle)) + { + ctab_handle = (*aw_handle)->awCTable; + HandToHand ((Handle *) &ctab_handle); + ct_table = (*ctab_handle)->ctTable; + ct_size = (*ctab_handle)->ctSize; + while (ct_size > -1) + { + if (ct_table->value == 0) + { + ct_table->rgb = bg_color; + CTabChanged (ctab_handle); + SetWinColor (w, (WCTabHandle) ctab_handle); + } + ct_size--; + } + } +#endif +} + +/* Flush display of frame F, or of all frames if F is null. */ + +void +x_flush (f) + struct frame *f; +{ +#if TARGET_API_MAC_CARBON + BLOCK_INPUT; +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (f); +#endif + if (f) + QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL); + else + QDFlushPortBuffer (GetQDGlobalsThePort (), NULL); + UNBLOCK_INPUT; +#endif +} + +#if USE_CG_DRAWING +void +mac_flush_display_optional (f) + struct frame *f; +{ + BLOCK_INPUT; + mac_prepare_for_quickdraw (f); + UNBLOCK_INPUT; +} +#endif + +void +mac_update_begin (f) + struct frame *f; +{ +#if TARGET_API_MAC_CARBON + /* During update of a frame, availability of input events is + periodically checked with ReceiveNextEvent if + redisplay-dont-pause is nil. That normally flushes window buffer + changes for every check, and thus screen update looks waving even + if no input is available. So we disable screen updates during + update of a frame. */ + DisableScreenUpdates (); +#endif +} + +void +mac_update_end (f) + struct frame *f; +{ +#if TARGET_API_MAC_CARBON + EnableScreenUpdates (); +#endif +} + +void +mac_frame_up_to_date (f) + struct frame *f; +{ + /* Nothing to do. */ +} + +void +mac_create_frame_window (f, tooltip_p) + struct frame *f; + int tooltip_p; +{ + Rect r; +#if TARGET_API_MAC_CARBON + WindowClass window_class; + WindowAttributes attributes; +#else + short proc_id; + WindowRef behind; + Boolean go_away_flag; +#endif + + if (!tooltip_p) + { + SetRect (&r, f->left_pos, f->top_pos, + f->left_pos + FRAME_PIXEL_WIDTH (f), + f->top_pos + FRAME_PIXEL_HEIGHT (f)); +#if TARGET_API_MAC_CARBON + window_class = kDocumentWindowClass; + attributes = (kWindowStandardDocumentAttributes +#ifdef MAC_OSX + | kWindowToolbarButtonAttribute +#endif + ); +#else + proc_id = zoomDocProc; + behind = (WindowRef) -1; + go_away_flag = true; +#endif + } + else + { + SetRect (&r, 0, 0, 1, 1); +#if TARGET_API_MAC_CARBON + window_class = kHelpWindowClass; + attributes = (kWindowNoUpdatesAttribute + | kWindowNoActivatesAttribute +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 + | kWindowIgnoreClicksAttribute +#endif + ); +#else + proc_id = plainDBox; + behind = NULL; + go_away_flag = false; +#endif + } + +#if TARGET_API_MAC_CARBON + CreateNewWindow (window_class, attributes, &r, &FRAME_MAC_WINDOW (f)); + if (FRAME_MAC_WINDOW (f)) + { + SetWRefCon (FRAME_MAC_WINDOW (f), (long) f->output_data.mac); + if (!tooltip_p) + if (install_window_handler (FRAME_MAC_WINDOW (f)) != noErr) + { + DisposeWindow (FRAME_MAC_WINDOW (f)); + FRAME_MAC_WINDOW (f) = NULL; + } + } +#else /* !TARGET_API_MAC_CARBON */ + FRAME_MAC_WINDOW (f) + = NewCWindow (NULL, &r, "\p", false, proc_id, behind, go_away_flag, + (long) f->output_data.mac); +#endif /* !TARGET_API_MAC_CARBON */ + /* so that update events can find this mac_output struct */ + f->output_data.mac->mFP = f; /* point back to emacs frame */ + +#ifndef MAC_OSX + if (!tooltip_p) + if (FRAME_MAC_WINDOW (f)) + { + ControlRef root_control; + + if (CreateRootControl (FRAME_MAC_WINDOW (f), &root_control) != noErr) + { + DisposeWindow (FRAME_MAC_WINDOW (f)); + FRAME_MAC_WINDOW (f) = NULL; + } + } +#endif +} + +/* Dispose of the Mac window of the frame F. */ + +void +mac_dispose_frame_window (f) + struct frame *f; +{ + WindowRef window = FRAME_MAC_WINDOW (f); + + if (window != tip_window) + remove_window_handler (window); + +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (f); +#endif + DisposeWindow (window); +} + + +/************************************************************************ + View and Drawing + ************************************************************************/ + +#if USE_CG_DRAWING +#define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context) + +CGContextRef +mac_begin_cg_clip (f, gc) + struct frame *f; + GC gc; +{ + CGContextRef context = FRAME_CG_CONTEXT (f); + + if (!context) + { + QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context); + FRAME_CG_CONTEXT (f) = context; + } + + CGContextSaveGState (context); + CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f)); + CGContextScaleCTM (context, 1, -1); + if (gc && gc->n_clip_rects) + CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects); + + return context; +} + +void +mac_end_cg_clip (f) + struct frame *f; +{ + CGContextRestoreGState (FRAME_CG_CONTEXT (f)); +} + +static void +mac_prepare_for_quickdraw (f) + struct frame *f; +{ + if (f == NULL) + { + Lisp_Object rest, frame; + FOR_EACH_FRAME (rest, frame) + if (FRAME_MAC_P (XFRAME (frame))) + mac_prepare_for_quickdraw (XFRAME (frame)); + } + else + { + CGContextRef context = FRAME_CG_CONTEXT (f); + + if (context) + { + CGContextSynchronize (context); + QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), + &FRAME_CG_CONTEXT (f)); + } + } +} +#endif + +static RgnHandle saved_port_clip_region = NULL; + +void +mac_begin_clip (f, gc) + struct frame *f; + GC gc; +{ + static RgnHandle new_region = NULL; + + if (saved_port_clip_region == NULL) + saved_port_clip_region = NewRgn (); + if (new_region == NULL) + new_region = NewRgn (); + +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (f); +#endif + SetPortWindowPort (FRAME_MAC_WINDOW (f)); + + if (gc && gc->n_clip_rects) + { + GetClip (saved_port_clip_region); + SectRgn (saved_port_clip_region, gc->clip_region, new_region); + SetClip (new_region); + } +} + +void +mac_end_clip (f, gc) + struct frame *f; + GC gc; +{ + if (gc && gc->n_clip_rects) + SetClip (saved_port_clip_region); +} + +#if TARGET_API_MAC_CARBON +/* Mac replacement for XCopyArea: used only for scrolling. */ + +void +mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y) + struct frame *f; + GC gc; + int src_x, src_y; + unsigned int width, height; + int dest_x, dest_y; +{ + Rect src_r; + RgnHandle dummy = NewRgn (); /* For avoiding update events. */ + + SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (f); +#endif + ScrollWindowRect (FRAME_MAC_WINDOW (f), + &src_r, dest_x - src_x, dest_y - src_y, + kScrollWindowNoOptions, dummy); + DisposeRgn (dummy); +} +#endif + + +/************************************************************************ + Scroll bars + ************************************************************************/ + +extern struct scroll_bar *tracked_scroll_bar; +extern Lisp_Object last_mouse_scroll_bar; +extern Time last_mouse_movement_time; + +static void x_scroll_bar_handle_click P_ ((struct scroll_bar *, + ControlPartCode, + const EventRecord *, + struct input_event *)); +#ifndef USE_TOOLKIT_SCROLL_BARS +static void x_scroll_bar_note_movement P_ ((struct scroll_bar *, int, Time)); +#else /* USE_TOOLKIT_SCROLL_BARS */ +static void x_scroll_bar_handle_press P_ ((struct scroll_bar *, + ControlPartCode, Point, + struct input_event *)); +static void x_scroll_bar_handle_release P_ ((struct scroll_bar *, + struct input_event *)); +static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *, + Point, struct input_event *)); +static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *)); +static OSStatus install_scroll_bar_timer P_ ((void)); +static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval)); +static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode)); +static void construct_scroll_bar_click P_ ((struct scroll_bar *, int, + struct input_event *)); +static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode, + Rect *)); +static void update_scroll_bar_track_info P_ ((struct scroll_bar *)); + +/* Last scroll bar part sent in x_scroll_bar_handle_*. */ + +static int last_scroll_bar_part; + +static EventLoopTimerRef scroll_bar_timer; + +static int scroll_bar_timer_event_posted_p; + +#define SCROLL_BAR_FIRST_DELAY 0.5 +#define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15) + +static pascal void +scroll_bar_timer_callback (timer, data) + EventLoopTimerRef timer; + void *data; +{ + OSStatus err; + + err = mac_post_mouse_moved_event (); + if (err == noErr) + scroll_bar_timer_event_posted_p = 1; +} + +static OSStatus +install_scroll_bar_timer () +{ + static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL; + + if (scroll_bar_timer_callbackUPP == NULL) + scroll_bar_timer_callbackUPP = + NewEventLoopTimerUPP (scroll_bar_timer_callback); + + if (scroll_bar_timer == NULL) + /* Mac OS X and CarbonLib 1.5 and later allow us to specify + kEventDurationForever as delays. */ + return + InstallEventLoopTimer (GetCurrentEventLoop (), + kEventDurationForever, kEventDurationForever, + scroll_bar_timer_callbackUPP, NULL, + &scroll_bar_timer); +} + +static OSStatus +set_scroll_bar_timer (delay) + EventTimerInterval delay; +{ + if (scroll_bar_timer == NULL) + install_scroll_bar_timer (); + + scroll_bar_timer_event_posted_p = 0; + + return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay); +} + +static int +control_part_code_to_scroll_bar_part (part_code) + ControlPartCode part_code; +{ + switch (part_code) + { + case kControlUpButtonPart: return scroll_bar_up_arrow; + case kControlDownButtonPart: return scroll_bar_down_arrow; + case kControlPageUpPart: return scroll_bar_above_handle; + case kControlPageDownPart: return scroll_bar_below_handle; + case kControlIndicatorPart: return scroll_bar_handle; + } + + return -1; +} + +static void +construct_scroll_bar_click (bar, part, bufp) + struct scroll_bar *bar; + int part; + struct input_event *bufp; +{ + bufp->kind = SCROLL_BAR_CLICK_EVENT; + bufp->frame_or_window = bar->window; + bufp->arg = Qnil; + bufp->part = part; + bufp->code = 0; + XSETINT (bufp->x, 0); + XSETINT (bufp->y, 0); + bufp->modifiers = 0; +} + +static OSStatus +get_control_part_bounds (ch, part_code, rect) + ControlRef ch; + ControlPartCode part_code; + Rect *rect; +{ + RgnHandle region = NewRgn (); + OSStatus err; + + err = GetControlRegion (ch, part_code, region); + if (err == noErr) + GetRegionBounds (region, rect); + DisposeRgn (region); + + return err; +} + +static void +x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp) + struct scroll_bar *bar; + ControlPartCode part_code; + Point mouse_pos; + struct input_event *bufp; +{ + int part = control_part_code_to_scroll_bar_part (part_code); + + if (part < 0) + return; + + if (part != scroll_bar_handle) + { + construct_scroll_bar_click (bar, part, bufp); + HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code); + set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY); + bar->dragging = Qnil; + } + else + { + Rect r; + + get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar), + kControlIndicatorPart, &r); + XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1); + } + + last_scroll_bar_part = part; + tracked_scroll_bar = bar; +} + +static void +x_scroll_bar_handle_release (bar, bufp) + struct scroll_bar *bar; + struct input_event *bufp; +{ + if (last_scroll_bar_part != scroll_bar_handle + || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0)) + construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp); + + HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0); + set_scroll_bar_timer (kEventDurationForever); + + last_scroll_bar_part = -1; + bar->dragging = Qnil; + tracked_scroll_bar = NULL; +} + +static void +x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp) + WindowRef win; + struct scroll_bar *bar; + Point mouse_pos; + struct input_event *bufp; +{ + ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); + + if (last_scroll_bar_part == scroll_bar_handle) + { + int top, top_range; + Rect r; + + get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar), + kControlIndicatorPart, &r); + + if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0) + XSETINT (bar->dragging, - (XINT (bar->dragging) + 1)); + + top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top); + top_range = XINT (bar->track_height) - XINT (bar->min_handle); + + if (top < 0) + top = 0; + if (top > top_range) + top = top_range; + + construct_scroll_bar_click (bar, scroll_bar_handle, bufp); + XSETINT (bufp->x, top); + XSETINT (bufp->y, top_range); + } + else + { + ControlPartCode part_code; + int unhilite_p = 0, part; + + if (ch != FindControlUnderMouse (mouse_pos, win, &part_code)) + unhilite_p = 1; + else + { + part = control_part_code_to_scroll_bar_part (part_code); + + switch (last_scroll_bar_part) + { + case scroll_bar_above_handle: + case scroll_bar_below_handle: + if (part != scroll_bar_above_handle + && part != scroll_bar_below_handle) + unhilite_p = 1; + break; + + case scroll_bar_up_arrow: + case scroll_bar_down_arrow: + if (part != scroll_bar_up_arrow + && part != scroll_bar_down_arrow) + unhilite_p = 1; + break; + } + } + + if (unhilite_p) + HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0); + else if (part != last_scroll_bar_part + || scroll_bar_timer_event_posted_p) + { + construct_scroll_bar_click (bar, part, bufp); + last_scroll_bar_part = part; + HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code); + set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY); + } + } +} + +/* Update BAR->track_top, BAR->track_height, and BAR->min_handle for + the scroll bar BAR. This function should be called when the bounds + of the scroll bar is changed. */ + +static void +update_scroll_bar_track_info (bar) + struct scroll_bar *bar; +{ + ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); + Rect r0, r1; + + GetControlBounds (ch, &r0); + + if (r0.right - r0.left >= r0.bottom - r0.top +#ifdef MAC_OSX + || r0.right - r0.left < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH +#endif + ) + { + XSETINT (bar->track_top, 0); + XSETINT (bar->track_height, 0); + XSETINT (bar->min_handle, 0); + } + else + { + BLOCK_INPUT; + + SetControl32BitMinimum (ch, 0); + SetControl32BitMaximum (ch, 1 << 30); + SetControlViewSize (ch, 1); + + /* Move the scroll bar thumb to the top. */ + SetControl32BitValue (ch, 0); + get_control_part_bounds (ch, kControlIndicatorPart, &r0); + + /* Move the scroll bar thumb to the bottom. */ + SetControl32BitValue (ch, 1 << 30); + get_control_part_bounds (ch, kControlIndicatorPart, &r1); + + UnionRect (&r0, &r1, &r0); + XSETINT (bar->track_top, r0.top); + XSETINT (bar->track_height, r0.bottom - r0.top); + XSETINT (bar->min_handle, r1.bottom - r1.top); + + /* Don't show the scroll bar if its height is not enough to + display the scroll bar thumb. */ + if (r0.bottom - r0.top > 0) + ShowControl (ch); + + UNBLOCK_INPUT; + } +} + +/* Set the thumb size and position of scroll bar BAR. We are currently + displaying PORTION out of a whole WHOLE, and our position POSITION. */ + +void +x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole) + struct scroll_bar *bar; + int portion, position, whole; +{ + ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); + int value, viewsize, maximum; + + if (XINT (bar->track_height) == 0) + return; + + if (whole <= portion) + value = 0, viewsize = 1, maximum = 0; + else + { + float scale; + + maximum = XINT (bar->track_height) - XINT (bar->min_handle); + scale = (float) maximum / (whole - portion); + value = position * scale + 0.5f; + viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle); + } + + BLOCK_INPUT; + + if (GetControlViewSize (ch) != viewsize + || GetControl32BitValue (ch) != value + || GetControl32BitMaximum (ch) != maximum) + { + /* Temporarily hide the scroll bar to avoid multiple redraws. */ + SetControlVisibility (ch, false, false); + + SetControl32BitMaximum (ch, maximum); + SetControl32BitValue (ch, value); + SetControlViewSize (ch, viewsize); + + SetControlVisibility (ch, true, true); + } + + UNBLOCK_INPUT; +} + +#endif /* USE_TOOLKIT_SCROLL_BARS */ + +/* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies + the initial geometry and visibility, respectively. The created + control is stored in some members of BAR. */ + +void +mac_create_scroll_bar (bar, bounds, visible) + struct scroll_bar *bar; + const Rect *bounds; + Boolean visible; +{ + struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + ControlRef ch; + +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (f); +#endif + ch = NewControl (FRAME_MAC_WINDOW (f), bounds, "\p", visible, 0, 0, 0, +#if TARGET_API_MAC_CARBON + kControlScrollBarProc, +#else + scrollBarProc, +#endif + (SInt32) bar); + SET_SCROLL_BAR_CONTROL_REF (bar, ch); + + XSETINT (bar->start, 0); + XSETINT (bar->end, 0); + bar->dragging = Qnil; + +#ifdef USE_TOOLKIT_SCROLL_BARS + update_scroll_bar_track_info (bar); +#endif +} + +/* Dispose of the scroll bar control stored in some members of + BAR. */ + +void +mac_dispose_scroll_bar (bar) + struct scroll_bar *bar; +{ +#if USE_CG_DRAWING + struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + + mac_prepare_for_quickdraw (f); +#endif + DisposeControl (SCROLL_BAR_CONTROL_REF (bar)); +} + +/* Set bounds of the scroll bar BAR to BOUNDS. */ + +void +mac_set_scroll_bar_bounds (bar, bounds) + struct scroll_bar *bar; + const Rect *bounds; +{ + ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); + SInt16 width, height; +#if USE_CG_DRAWING + struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + + mac_prepare_for_quickdraw (f); +#endif + + width = bounds->right - bounds->left; + height = bounds->bottom - bounds->top; + HideControl (ch); + MoveControl (ch, bounds->left, bounds->top); + SizeControl (ch, width, height); +#ifdef USE_TOOLKIT_SCROLL_BARS + update_scroll_bar_track_info (bar); +#else + if (width < height) + ShowControl (ch); +#endif +} + +/* Draw the scroll bar BAR. */ + +void +mac_redraw_scroll_bar (bar) + struct scroll_bar *bar; +{ +#if USE_CG_DRAWING + struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + + mac_prepare_for_quickdraw (f); +#endif + Draw1Control (SCROLL_BAR_CONTROL_REF (bar)); +} + +/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind + is set to something other than NO_EVENT, it is enqueued. + + This may be called from a signal handler, so we have to ignore GC + mark bits. */ + +static void +x_scroll_bar_handle_click (bar, part_code, er, bufp) + struct scroll_bar *bar; + ControlPartCode part_code; + const EventRecord *er; + struct input_event *bufp; +{ + int win_y, top_range; + + if (! GC_WINDOWP (bar->window)) + abort (); + + bufp->kind = SCROLL_BAR_CLICK_EVENT; + bufp->frame_or_window = bar->window; + bufp->arg = Qnil; + + bar->dragging = Qnil; + + switch (part_code) + { + case kControlUpButtonPart: + bufp->part = scroll_bar_up_arrow; + break; + case kControlDownButtonPart: + bufp->part = scroll_bar_down_arrow; + break; + case kControlPageUpPart: + bufp->part = scroll_bar_above_handle; + break; + case kControlPageDownPart: + bufp->part = scroll_bar_below_handle; + break; +#if TARGET_API_MAC_CARBON + default: +#else + case kControlIndicatorPart: +#endif + if (er->what == mouseDown) + bar->dragging = make_number (0); + XSETVECTOR (last_mouse_scroll_bar, bar); + bufp->part = scroll_bar_handle; + break; + } + + win_y = XINT (bufp->y) - XINT (bar->top); + top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height)); + + win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER; + + win_y -= 24; + + if (! NILP (bar->dragging)) + win_y -= XINT (bar->dragging); + + if (win_y < 0) + win_y = 0; + if (win_y > top_range) + win_y = top_range; + + XSETINT (bufp->x, win_y); + XSETINT (bufp->y, top_range); +} + +/* Return information to the user about the current position of the mouse + on the scroll bar. */ + +void +x_scroll_bar_report_motion (fp, bar_window, part, x, y, time) + FRAME_PTR *fp; + Lisp_Object *bar_window; + enum scroll_bar_part *part; + Lisp_Object *x, *y; + unsigned long *time; +{ + struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar); + ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); +#if TARGET_API_MAC_CARBON + WindowRef wp = GetControlOwner (ch); +#else + WindowRef wp = (*ch)->contrlOwner; +#endif + Point mouse_pos; + struct frame *f = mac_window_to_frame (wp); + int win_y, top_range; + +#if TARGET_API_MAC_CARBON + GetGlobalMouse (&mouse_pos); + mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); + mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); +#else + SetPortWindowPort (wp); + GetMouse (&mouse_pos); +#endif + + win_y = mouse_pos.v - XINT (bar->top); + top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)); + + win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER; + + win_y -= 24; + + if (! NILP (bar->dragging)) + win_y -= XINT (bar->dragging); + + if (win_y < 0) + win_y = 0; + if (win_y > top_range) + win_y = top_range; + + *fp = f; + *bar_window = bar->window; + + if (! NILP (bar->dragging)) + *part = scroll_bar_handle; + else if (win_y < XINT (bar->start)) + *part = scroll_bar_above_handle; + else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE) + *part = scroll_bar_handle; + else + *part = scroll_bar_below_handle; + + XSETINT (*x, win_y); + XSETINT (*y, top_range); + + f->mouse_moved = 0; + last_mouse_scroll_bar = Qnil; + + *time = last_mouse_movement_time; +} + +#ifndef USE_TOOLKIT_SCROLL_BARS +/* Draw BAR's handle in the proper position. + + If the handle is already drawn from START to END, don't bother + redrawing it, unless REBUILD is non-zero; in that case, always + redraw it. (REBUILD is handy for drawing the handle after expose + events.) + + Normally, we want to constrain the start and end of the handle to + fit inside its rectangle, but if the user is dragging the scroll + bar handle, we want to let them drag it down all the way, so that + the bar's top is as far down as it goes; otherwise, there's no way + to move to the very end of the buffer. */ + +void +x_scroll_bar_set_handle (bar, start, end, rebuild) + struct scroll_bar *bar; + int start, end; + int rebuild; +{ + int dragging = ! NILP (bar->dragging); + ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); + FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)); + int length = end - start; + + /* If the display is already accurate, do nothing. */ + if (! rebuild + && start == XINT (bar->start) + && end == XINT (bar->end)) + return; + + BLOCK_INPUT; + + /* Make sure the values are reasonable, and try to preserve the + distance between start and end. */ + if (start < 0) + start = 0; + else if (start > top_range) + start = top_range; + end = start + length; + + if (end < start) + end = start; + else if (end > top_range && ! dragging) + end = top_range; + + /* Store the adjusted setting in the scroll bar. */ + XSETINT (bar->start, start); + XSETINT (bar->end, end); + + /* Clip the end position, just for display. */ + if (end > top_range) + end = top_range; + + /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below + top positions, to make sure the handle is always at least that + many pixels tall. */ + end += VERTICAL_SCROLL_BAR_MIN_HANDLE; + + SetControlMinimum (ch, 0); + /* Don't inadvertently activate deactivated scroll bars */ + if (GetControlMaximum (ch) != -1) + SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE + - (end - start)); + SetControlValue (ch, start); +#if TARGET_API_MAC_CARBON + SetControlViewSize (ch, end - start); +#endif + + UNBLOCK_INPUT; +} + +/* Handle some mouse motion while someone is dragging the scroll bar. + + This may be called from a signal handler, so we have to ignore GC + mark bits. */ + +static void +x_scroll_bar_note_movement (bar, y_pos, t) + struct scroll_bar *bar; + int y_pos; + Time t; +{ + FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame); + + last_mouse_movement_time = t; + + f->mouse_moved = 1; + XSETVECTOR (last_mouse_scroll_bar, bar); + + /* If we're dragging the bar, display it. */ + if (! GC_NILP (bar->dragging)) + { + /* Where should the handle be now? */ + int new_start = y_pos - 24; + + if (new_start != XINT (bar->start)) + { + int new_end = new_start + (XINT (bar->end) - XINT (bar->start)); + + x_scroll_bar_set_handle (bar, new_start, new_end, 0); + } + } +} +#endif /* !USE_TOOLKIT_SCROLL_BARS */ + + +/*********************************************************************** + Tool-bars + ***********************************************************************/ + +#if USE_MAC_TOOLBAR +/* In identifiers such as function/variable names, Emacs tool bar is + referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */ + +#define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar")) +#define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon")) + +#define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0' +#define TOOLBAR_ITEM_COMMAND_ID_P(id) \ + (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET) +#define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \ + ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET) +#define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \ + ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET) + +static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef, + EventRef, void *)); + +extern Rect last_mouse_glyph; + +extern void mac_move_window_with_gravity P_ ((struct frame *, int, + short, short)); +extern void mac_get_window_origin_with_gravity P_ ((struct frame *, int, + short *, short *)); +extern CGImageRef mac_image_spec_to_cg_image P_ ((struct frame *, + Lisp_Object)); + +static OSStatus +mac_handle_toolbar_event (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + OSStatus result = eventNotHandledErr; + + switch (GetEventKind (event)) + { + case kEventToolbarGetDefaultIdentifiers: + result = noErr; + break; + + case kEventToolbarGetAllowedIdentifiers: + { + CFMutableArrayRef array; + + GetEventParameter (event, kEventParamMutableArray, + typeCFMutableArrayRef, NULL, + sizeof (CFMutableArrayRef), NULL, &array); + CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER); + result = noErr; + } + break; + + case kEventToolbarCreateItemWithIdentifier: + { + CFStringRef identifier; + HIToolbarItemRef item = NULL; + + GetEventParameter (event, kEventParamToolbarItemIdentifier, + typeCFStringRef, NULL, + sizeof (CFStringRef), NULL, &identifier); + + if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0) + == kCFCompareEqualTo) + HIToolbarItemCreate (identifier, + kHIToolbarItemAllowDuplicates + | kHIToolbarItemCantBeRemoved, &item); + + if (item) + { + SetEventParameter (event, kEventParamToolbarItem, + typeHIToolbarItemRef, + sizeof (HIToolbarItemRef), &item); + result = noErr; + } + } + break; + + default: + abort (); + } + + return result; +} + +/* Create a tool bar for frame F. */ + +static OSStatus +mac_create_frame_tool_bar (f) + FRAME_PTR f; +{ + OSStatus err; + HIToolbarRef toolbar; + + err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes, + &toolbar); + if (err == noErr) + { + static const EventTypeSpec specs[] = + {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers}, + {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers}, + {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}}; + + err = InstallEventHandler (HIObjectGetEventTarget (toolbar), + mac_handle_toolbar_event, + GetEventTypeCount (specs), specs, + f, NULL); + } + + if (err == noErr) + err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly); + if (err == noErr) + { + static const EventTypeSpec specs[] = + {{kEventClassCommand, kEventCommandProcess}}; + + err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f), + mac_handle_toolbar_command_event, + GetEventTypeCount (specs), + specs, f, NULL); + } + if (err == noErr) + err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar); + + if (toolbar) + CFRelease (toolbar); + + return err; +} + +/* Update the tool bar for frame F. Add new buttons and remove old. */ + +void +update_frame_tool_bar (f) + FRAME_PTR f; +{ + HIToolbarRef toolbar = NULL; + short left, top; + CFArrayRef old_items = NULL; + CFIndex old_count; + int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity; + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + BLOCK_INPUT; + + GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar); + if (toolbar == NULL) + { + mac_create_frame_tool_bar (f); + GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar); + if (toolbar == NULL) + goto out; + if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity) + mac_get_window_origin_with_gravity (f, win_gravity, &left, &top); + } + + HIToolbarCopyItems (toolbar, &old_items); + if (old_items == NULL) + goto out; + + old_count = CFArrayGetCount (old_items); + pos = 0; + for (i = 0; i < f->n_tool_bar_items; ++i) + { +#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX)) + + int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)); + int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)); + int idx; + Lisp_Object image; + CGImageRef cg_image; + CFStringRef label; + HIToolbarItemRef item; + + /* If image is a vector, choose the image according to the + button state. */ + image = PROP (TOOL_BAR_ITEM_IMAGES); + if (VECTORP (image)) + { + if (enabled_p) + idx = (selected_p + ? TOOL_BAR_IMAGE_ENABLED_SELECTED + : TOOL_BAR_IMAGE_ENABLED_DESELECTED); + else + idx = (selected_p + ? TOOL_BAR_IMAGE_DISABLED_SELECTED + : TOOL_BAR_IMAGE_DISABLED_DESELECTED); + + xassert (ASIZE (image) >= idx); + image = AREF (image, idx); + } + else + idx = -1; + + cg_image = mac_image_spec_to_cg_image (f, image); + /* Ignore invalid image specifications. */ + if (cg_image == NULL) + continue; + + label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION)); + if (label == NULL) + label = CFSTR (""); + + if (pos < old_count) + { + CGImageRef old_cg_image = NULL; + CFStringRef old_label = NULL; + Boolean old_enabled_p; + + item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos); + + HIToolbarItemCopyImage (item, &old_cg_image); + if (cg_image != old_cg_image) + HIToolbarItemSetImage (item, cg_image); + CGImageRelease (old_cg_image); + + HIToolbarItemCopyLabel (item, &old_label); + if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo) + HIToolbarItemSetLabel (item, label); + CFRelease (old_label); + + old_enabled_p = HIToolbarItemIsEnabled (item); + if ((enabled_p || idx >= 0) != old_enabled_p) + HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0)); + } + else + { + item = NULL; + HIToolbarCreateItemWithIdentifier (toolbar, + TOOLBAR_ICON_ITEM_IDENTIFIER, + NULL, &item); + if (item) + { + HIToolbarItemSetImage (item, cg_image); + HIToolbarItemSetLabel (item, label); + HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0)); + HIToolbarAppendItem (toolbar, item); + CFRelease (item); + } + } + + CFRelease (label); + if (item) + { + HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i)); + pos++; + } + } + + CFRelease (old_items); + + while (pos < old_count) + HIToolbarRemoveItemAtIndex (toolbar, --old_count); + + ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true, + !win_gravity && f == mac_focus_frame (dpyinfo)); + /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on + toolbar visibility change. */ + mac_handle_origin_change (f); + if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity) + { + mac_move_window_with_gravity (f, win_gravity, left, top); + /* If the title bar is completely outside the screen, adjust the + position. */ + ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, + kWindowConstrainMoveRegardlessOfFit + | kWindowConstrainAllowPartial, NULL, NULL); + f->output_data.mac->toolbar_win_gravity = 0; + } + + out: + UNBLOCK_INPUT; +} + +/* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it + doesn't deallocate the resources. */ + +void +free_frame_tool_bar (f) + FRAME_PTR f; +{ + if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f))) + { + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + BLOCK_INPUT; + ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false, + (NILP (find_symbol_value + (intern ("frame-notice-user-settings"))) + && f == mac_focus_frame (dpyinfo))); + /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events + on toolbar visibility change. */ + mac_handle_origin_change (f); + UNBLOCK_INPUT; + } +} + +/* Report a mouse movement over toolbar to the mainstream Emacs + code. */ + +static void +mac_tool_bar_note_mouse_movement (f, event) + struct frame *f; + EventRef event; +{ + OSStatus err; + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + int mouse_down_p; + WindowRef window; + WindowPartCode part_code; + HIViewRef item_view; + UInt32 command_id; + + mouse_down_p = (dpyinfo->grabbed + && f == last_mouse_frame + && FRAME_LIVE_P (f)); + if (mouse_down_p) + return; + + err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef, NULL, + sizeof (WindowRef), NULL, &window); + if (err != noErr || window != FRAME_MAC_WINDOW (f)) + return; + + err = GetEventParameter (event, kEventParamWindowPartCode, + typeWindowPartCode, NULL, + sizeof (WindowPartCode), NULL, &part_code); + if (err != noErr || part_code != inStructure) + return; + + err = HIViewGetViewForMouseEvent (HIViewGetRoot (window), event, &item_view); + /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a + toolbar item view seems to have the same command ID with that of + the toolbar item. */ + if (err == noErr) + err = GetControlCommandID (item_view, &command_id); + if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id)) + { + int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id); + + if (i < f->n_tool_bar_items) + { + HIRect bounds; + HIViewRef content_view; + + err = HIViewGetBounds (item_view, &bounds); + if (err == noErr) + err = HIViewFindByID (HIViewGetRoot (window), + kHIViewWindowContentID, &content_view); + if (err == noErr) + err = HIViewConvertRect (&bounds, item_view, content_view); + if (err == noErr) + SetRect (&last_mouse_glyph, + CGRectGetMinX (bounds), CGRectGetMinY (bounds), + CGRectGetMaxX (bounds), CGRectGetMaxY (bounds)); + + help_echo_object = help_echo_window = Qnil; + help_echo_pos = -1; + help_echo_string = PROP (TOOL_BAR_ITEM_HELP); + if (NILP (help_echo_string)) + help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION); + } + } +} + +static OSStatus +mac_handle_toolbar_command_event (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + OSStatus err, result = eventNotHandledErr; + struct frame *f = (struct frame *) data; + HICommand command; + + err = GetEventParameter (event, kEventParamDirectObject, + typeHICommand, NULL, + sizeof (HICommand), NULL, &command); + if (err != noErr) + return result; + + switch (GetEventKind (event)) + { + case kEventCommandProcess: + if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID)) + result = CallNextEventHandler (next_handler, event); + else + { + int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID); + + if (i < f->n_tool_bar_items + && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P))) + { + Lisp_Object frame; + struct input_event buf; + + EVENT_INIT (buf); + + XSETFRAME (frame, f); + buf.kind = TOOL_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = frame; + kbd_buffer_store_event (&buf); + + buf.kind = TOOL_BAR_EVENT; + buf.frame_or_window = frame; + buf.arg = PROP (TOOL_BAR_ITEM_KEY); + buf.modifiers = mac_event_to_emacs_modifiers (event); + kbd_buffer_store_event (&buf); + + result = noErr; + } + } + break; + + default: + abort (); + } +#undef PROP + + return result; +} +#endif /* USE_MAC_TOOLBAR */ + + +/*********************************************************************** + Font Panel + ***********************************************************************/ + +#if USE_MAC_FONT_PANEL +/* Whether Font Panel has been shown before. The first call to font + panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is + slow. This variable is used for deferring such a call as much as + possible. */ +static int font_panel_shown_p = 0; + +extern Lisp_Object Qpanel_closed, Qselection; +extern Lisp_Object Qfont; + +/* Whether the font panel is currently visible. */ + +int +mac_font_panel_visible_p () +{ + return font_panel_shown_p && FPIsFontPanelVisible (); +} + +static pascal OSStatus +mac_handle_font_event (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + OSStatus result, err; + Lisp_Object id_key; + int num_params; + const EventParamName *names; + const EventParamType *types; + static const EventParamName names_sel[] = {kEventParamATSUFontID, + kEventParamATSUFontSize, + kEventParamFMFontFamily, + kEventParamFMFontStyle, + kEventParamFMFontSize, + kEventParamFontColor}; + static const EventParamType types_sel[] = {typeATSUFontID, + typeATSUSize, + typeFMFontFamily, + typeFMFontStyle, + typeFMFontSize, + typeFontColor}; + + result = CallNextEventHandler (next_handler, event); + if (result != eventNotHandledErr) + return result; + + switch (GetEventKind (event)) + { + case kEventFontPanelClosed: + id_key = Qpanel_closed; + num_params = 0; + names = NULL; + types = NULL; + break; + + case kEventFontSelection: + id_key = Qselection; + num_params = sizeof (names_sel) / sizeof (names_sel[0]); + names = names_sel; + types = types_sel; + break; + } + + err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key, + event, num_params, + names, types); + if (err == noErr) + result = noErr; + + return result; +} + +/* Toggle visiblity of the font panel. */ + +OSStatus +mac_show_hide_font_panel () +{ + if (!font_panel_shown_p) + { + OSStatus err; + + static const EventTypeSpec specs[] = + {{kEventClassFont, kEventFontPanelClosed}, + {kEventClassFont, kEventFontSelection}}; + + err = InstallApplicationEventHandler (mac_handle_font_event, + GetEventTypeCount (specs), + specs, NULL, NULL); + if (err != noErr) + return err; + + font_panel_shown_p = 1; + } + + return FPShowHideFontPanel (); +} + +/* Set the font selected in the font panel to the one corresponding to + the face FACE_ID and the charcacter C in the frame F. */ + +OSStatus +mac_set_font_info_for_selection (f, face_id, c) + struct frame *f; + int face_id, c; +{ + OSStatus err; + EventTargetRef target = NULL; + XFontStruct *font = NULL; + + if (!mac_font_panel_visible_p ()) + return noErr; + + if (f) + { + target = GetWindowEventTarget (FRAME_MAC_WINDOW (f)); + + if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0)) + { + struct face *face; + + face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c); + face = FACE_FROM_ID (f, face_id); + font = face->font; + } + } + + if (font == NULL) + err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target); + else + { + if (font->mac_fontnum != -1) + { + FontSelectionQDStyle qd_style; + + qd_style.version = kFontSelectionQDStyleVersionZero; + qd_style.instance.fontFamily = font->mac_fontnum; + qd_style.instance.fontStyle = font->mac_fontface; + qd_style.size = font->mac_fontsize; + qd_style.hasColor = false; + + err = SetFontInfoForSelection (kFontSelectionQDType, + 1, &qd_style, target); + } + else + err = SetFontInfoForSelection (kFontSelectionATSUIType, + 1, &font->mac_style, target); + } + + return err; +} +#endif /* USE_MAC_FONT_PANEL */ + + +/************************************************************************ + Event Handling + ************************************************************************/ + +/* Non-zero means that a HELP_EVENT has been generated since Emacs + start. */ + +static int any_help_event_p; + +/* Last window where we saw the mouse. Used by mouse-autoselect-window. */ +static Lisp_Object last_window; + +static Point saved_menu_event_location; + +extern struct frame *pending_autoraise_frame; + +extern FRAME_PTR last_mouse_glyph_frame; + +#ifdef __STDC__ +extern int volatile input_signal_count; +#else +extern int input_signal_count; +#endif + +extern int mac_screen_config_changed; + +extern Lisp_Object Vmac_emulate_three_button_mouse; +#if TARGET_API_MAC_CARBON +extern int mac_wheel_button_is_mouse_2; +extern int mac_pass_command_to_system; +extern int mac_pass_control_to_system; +#endif /* TARGET_API_MAC_CARBON */ +extern int mac_ready_for_apple_events; + +extern void mac_focus_changed P_ ((int, struct mac_display_info *, + struct frame *, struct input_event *)); +extern int mac_get_emulated_btn P_ ((UInt32)); +extern int note_mouse_movement P_ ((FRAME_PTR, Point *)); +extern void mac_get_screen_info P_ ((struct mac_display_info *)); + +/* The focus may have changed. Figure out if it is a real focus change, + by checking both FocusIn/Out and Enter/LeaveNotify events. + + Returns FOCUS_IN_EVENT event in *BUFP. */ + +static void +x_detect_focus_change (dpyinfo, event, bufp) + struct mac_display_info *dpyinfo; + const EventRecord *event; + struct input_event *bufp; +{ + struct frame *frame; + + frame = mac_window_to_frame ((WindowRef) event->message); + if (! frame) + return; + + /* On Mac, this is only called from focus events, so no switch needed. */ + mac_focus_changed ((event->modifiers & activeFlag), + dpyinfo, frame, bufp); +} + +#if TARGET_API_MAC_CARBON +/* Obtains the event modifiers from the event EVENTREF and then calls + mac_to_emacs_modifiers. */ + +static int +mac_event_to_emacs_modifiers (EventRef eventRef) +{ + UInt32 mods = 0, class; + + GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL, + sizeof (UInt32), NULL, &mods); + class = GetEventClass (eventRef); + if (!NILP (Vmac_emulate_three_button_mouse) && + (class == kEventClassMouse || class == kEventClassCommand)) + { + mods &= ~(optionKey | cmdKey); + } + return mac_to_emacs_modifiers (mods, 0); +} + +/* Given an event REF, return the code to use for the mouse button + code in the emacs input_event. */ + +static int +mac_get_mouse_btn (EventRef ref) +{ + EventMouseButton result = kEventMouseButtonPrimary; + GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL, + sizeof (EventMouseButton), NULL, &result); + switch (result) + { + case kEventMouseButtonPrimary: + if (NILP (Vmac_emulate_three_button_mouse)) + return 0; + else { + UInt32 mods = 0; + GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL, + sizeof (UInt32), NULL, &mods); + return mac_get_emulated_btn(mods); + } + case kEventMouseButtonSecondary: + return mac_wheel_button_is_mouse_2 ? 2 : 1; + case kEventMouseButtonTertiary: + case 4: /* 4 is the number for the mouse wheel button */ + return mac_wheel_button_is_mouse_2 ? 1 : 2; + default: + return 0; + } +} + +/* Normally, ConvertEventRefToEventRecord will correctly handle all + events. However the click of the mouse wheel is not converted to a + mouseDown or mouseUp event. Likewise for dead key events. This + calls ConvertEventRefToEventRecord, but then checks to see if it is + a mouse up/down, or a dead key Carbon event that has not been + converted, and if so, converts it by hand (to be picked up in the + XTread_socket loop). */ +static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec) +{ + OSStatus err; + Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec); + EventKind action; + + if (result) + return result; + + switch (GetEventClass (eventRef)) + { + case kEventClassMouse: + switch (GetEventKind (eventRef)) + { + case kEventMouseDown: + eventRec->what = mouseDown; + result = 1; + break; + + case kEventMouseUp: + eventRec->what = mouseUp; + result = 1; + break; + + default: + break; + } + break; + + case kEventClassKeyboard: + switch (GetEventKind (eventRef)) + { + case kEventRawKeyDown: + action = keyDown; + goto keystroke_common; + case kEventRawKeyRepeat: + action = autoKey; + goto keystroke_common; + case kEventRawKeyUp: + action = keyUp; + keystroke_common: + { + unsigned char char_codes; + UInt32 key_code; + + err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes, + typeChar, NULL, sizeof (char), + NULL, &char_codes); + if (err == noErr) + err = GetEventParameter (eventRef, kEventParamKeyCode, + typeUInt32, NULL, sizeof (UInt32), + NULL, &key_code); + if (err == noErr) + { + eventRec->what = action; + eventRec->message = char_codes | ((key_code & 0xff) << 8); + result = 1; + } + } + break; + + default: + break; + } + break; + + default: + break; + } + + if (result) + { + /* Need where and when. */ + UInt32 mods = 0; + + GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint, + NULL, sizeof (Point), NULL, &eventRec->where); + /* Use two step process because new event modifiers are 32-bit + and old are 16-bit. Currently, only loss is NumLock & Fn. */ + GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, + NULL, sizeof (UInt32), NULL, &mods); + eventRec->modifiers = mods; + + eventRec->when = EventTimeToTicks (GetEventTime (eventRef)); + } + + return result; +} +#endif /* TARGET_API_MAC_CARBON */ + +#if !TARGET_API_MAC_CARBON +static RgnHandle mouse_region = NULL; + +Boolean +mac_wait_next_event (er, sleep_time, dequeue) + EventRecord *er; + UInt32 sleep_time; + Boolean dequeue; +{ + static EventRecord er_buf = {nullEvent}; + UInt32 target_tick, current_tick; + EventMask event_mask; + + if (mouse_region == NULL) + mouse_region = NewRgn (); + + event_mask = everyEvent; + if (!mac_ready_for_apple_events) + event_mask -= highLevelEventMask; + + current_tick = TickCount (); + target_tick = current_tick + sleep_time; + + if (er_buf.what == nullEvent) + while (!WaitNextEvent (event_mask, &er_buf, + target_tick - current_tick, mouse_region)) + { + current_tick = TickCount (); + if (target_tick <= current_tick) + return false; + } + + *er = er_buf; + if (dequeue) + er_buf.what = nullEvent; + return true; +} +#endif /* not TARGET_API_MAC_CARBON */ + +#if TARGET_API_MAC_CARBON +OSStatus +mac_post_mouse_moved_event () +{ + EventRef event = NULL; + OSStatus err; + + err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0, + kEventAttributeNone, &event); + if (err == noErr) + { + Point mouse_pos; + + GetGlobalMouse (&mouse_pos); + err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint, + sizeof (Point), &mouse_pos); + } + if (err == noErr) + { + UInt32 modifiers = GetCurrentKeyModifiers (); + + err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32, + sizeof (UInt32), &modifiers); + } + if (err == noErr) + err = PostEventToQueue (GetCurrentEventQueue (), event, + kEventPriorityStandard); + if (event) + ReleaseEvent (event); + + return err; +} +#endif + +#ifdef MAC_OSX +/* Run the current run loop in the default mode until some input + happens or TIMEOUT seconds passes unless it is negative. Return + true if timeout occurs first. */ + +Boolean +mac_run_loop_run_once (timeout) + EventTimeout timeout; +{ +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (NULL); +#endif + return (CFRunLoopRunInMode (kCFRunLoopDefaultMode, + timeout >= 0 ? timeout : 100000, true) + == kCFRunLoopRunTimedOut); +} +#endif + +/* Emacs calls this whenever it wants to read an input event from the + user. */ + +int +XTread_socket (sd, expected, hold_quit) + int sd, expected; + struct input_event *hold_quit; +{ + struct input_event inev; + int count = 0; +#if TARGET_API_MAC_CARBON + EventRef eventRef; + EventTargetRef toolbox_dispatcher; +#endif + EventRecord er; + struct mac_display_info *dpyinfo = &one_mac_display_info; + + if (interrupt_input_blocked) + { + interrupt_input_pending = 1; + return -1; + } + + interrupt_input_pending = 0; + BLOCK_INPUT; + + /* So people can tell when we have read the available input. */ + input_signal_count++; + + ++handling_signal; + +#if TARGET_API_MAC_CARBON + toolbox_dispatcher = GetEventDispatcherTarget (); + + while ( +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (NULL), +#endif + !ReceiveNextEvent (0, NULL, kEventDurationNoWait, + kEventRemoveFromQueue, &eventRef)) +#else /* !TARGET_API_MAC_CARBON */ + while (mac_wait_next_event (&er, 0, true)) +#endif /* !TARGET_API_MAC_CARBON */ + { + int do_help = 0; + struct frame *f; + unsigned long timestamp; + + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; + +#if TARGET_API_MAC_CARBON + timestamp = GetEventTime (eventRef) / kEventDurationMillisecond; + + if (!mac_convert_event_ref (eventRef, &er)) + goto OTHER; +#else /* !TARGET_API_MAC_CARBON */ + timestamp = er.when * (1000 / 60); /* ticks to milliseconds */ +#endif /* !TARGET_API_MAC_CARBON */ + + switch (er.what) + { + case mouseDown: + case mouseUp: + { + WindowRef window_ptr; + ControlPartCode part_code; + int tool_bar_p = 0; + +#if TARGET_API_MAC_CARBON + OSStatus err; + + /* This is needed to send mouse events like aqua window + buttons to the correct handler. */ + read_socket_inev = &inev; + err = SendEventToEventTarget (eventRef, toolbox_dispatcher); + read_socket_inev = NULL; + if (err != eventNotHandledErr) + break; +#endif + last_mouse_glyph_frame = 0; + + if (dpyinfo->grabbed && last_mouse_frame + && FRAME_LIVE_P (last_mouse_frame)) + { + window_ptr = FRAME_MAC_WINDOW (last_mouse_frame); + part_code = inContent; + } + else + { + part_code = FindWindow (er.where, &window_ptr); + if (tip_window && window_ptr == tip_window) + { + HideWindow (tip_window); + part_code = FindWindow (er.where, &window_ptr); + } + } + + if (er.what != mouseDown + && (part_code != inContent || dpyinfo->grabbed == 0)) + break; + + switch (part_code) + { + case inMenuBar: + f = mac_focus_frame (dpyinfo); + saved_menu_event_location = er.where; + inev.kind = MENU_BAR_ACTIVATE_EVENT; + XSETFRAME (inev.frame_or_window, f); + break; + + case inContent: + if ( +#if TARGET_API_MAC_CARBON + FrontNonFloatingWindow () +#else + FrontWindow () +#endif + != window_ptr + || (mac_window_to_frame (window_ptr) + != dpyinfo->x_focus_frame)) + SelectWindow (window_ptr); + else + { + ControlPartCode control_part_code; + ControlRef ch; + Point mouse_loc; +#ifdef MAC_OSX + ControlKind control_kind; +#endif + + f = mac_window_to_frame (window_ptr); + /* convert to local coordinates of new window */ + mouse_loc.h = (er.where.h + - (f->left_pos + + FRAME_OUTER_TO_INNER_DIFF_X (f))); + mouse_loc.v = (er.where.v + - (f->top_pos + + FRAME_OUTER_TO_INNER_DIFF_Y (f))); +#if TARGET_API_MAC_CARBON + ch = FindControlUnderMouse (mouse_loc, window_ptr, + &control_part_code); +#ifdef MAC_OSX + if (ch) + GetControlKind (ch, &control_kind); +#endif +#else + control_part_code = FindControl (mouse_loc, window_ptr, + &ch); +#endif + +#if TARGET_API_MAC_CARBON + inev.code = mac_get_mouse_btn (eventRef); + inev.modifiers = mac_event_to_emacs_modifiers (eventRef); +#else + inev.code = mac_get_emulated_btn (er.modifiers); + inev.modifiers = mac_to_emacs_modifiers (er.modifiers, 0); +#endif + XSETINT (inev.x, mouse_loc.h); + XSETINT (inev.y, mouse_loc.v); + + if ((dpyinfo->grabbed && tracked_scroll_bar) + || (ch != 0 +#ifndef USE_TOOLKIT_SCROLL_BARS + /* control_part_code becomes kControlNoPart if + a progress indicator is clicked. */ + && control_part_code != kControlNoPart +#else /* USE_TOOLKIT_SCROLL_BARS */ +#ifdef MAC_OSX + && control_kind.kind == kControlKindScrollBar +#endif /* MAC_OSX */ +#endif /* USE_TOOLKIT_SCROLL_BARS */ + )) + { + struct scroll_bar *bar; + + if (dpyinfo->grabbed && tracked_scroll_bar) + { + bar = tracked_scroll_bar; +#ifndef USE_TOOLKIT_SCROLL_BARS + control_part_code = kControlIndicatorPart; +#endif + } + else + bar = (struct scroll_bar *) GetControlReference (ch); +#ifdef USE_TOOLKIT_SCROLL_BARS + /* Make the "Ctrl-Mouse-2 splits window" work + for toolkit scroll bars. */ + if (inev.modifiers & ctrl_modifier) + x_scroll_bar_handle_click (bar, control_part_code, + &er, &inev); + else if (er.what == mouseDown) + x_scroll_bar_handle_press (bar, control_part_code, + mouse_loc, &inev); + else + x_scroll_bar_handle_release (bar, &inev); +#else /* not USE_TOOLKIT_SCROLL_BARS */ + x_scroll_bar_handle_click (bar, control_part_code, + &er, &inev); + if (er.what == mouseDown + && control_part_code == kControlIndicatorPart) + tracked_scroll_bar = bar; + else + tracked_scroll_bar = NULL; +#endif /* not USE_TOOLKIT_SCROLL_BARS */ + } + else + { + Lisp_Object window; + int x = mouse_loc.h; + int y = mouse_loc.v; + + window = window_from_coordinates (f, x, y, 0, 0, 0, 1); + if (EQ (window, f->tool_bar_window)) + { + if (er.what == mouseDown) + handle_tool_bar_click (f, x, y, 1, 0); + else + handle_tool_bar_click (f, x, y, 0, + inev.modifiers); + tool_bar_p = 1; + } + else + { + XSETFRAME (inev.frame_or_window, f); + inev.kind = MOUSE_CLICK_EVENT; + } + } + + if (er.what == mouseDown) + { + dpyinfo->grabbed |= (1 << inev.code); + last_mouse_frame = f; + + if (!tool_bar_p) + last_tool_bar_item = -1; + } + else + { + if ((dpyinfo->grabbed & (1 << inev.code)) == 0) + /* If a button is released though it was not + previously pressed, that would be because + of multi-button emulation. */ + dpyinfo->grabbed = 0; + else + dpyinfo->grabbed &= ~(1 << inev.code); + } + + /* Ignore any mouse motion that happened before + this event; any subsequent mouse-movement Emacs + events should reflect only motion after the + ButtonPress. */ + if (f != 0) + f->mouse_moved = 0; + +#ifdef USE_TOOLKIT_SCROLL_BARS + if (inev.kind == MOUSE_CLICK_EVENT + || (inev.kind == SCROLL_BAR_CLICK_EVENT + && (inev.modifiers & ctrl_modifier))) +#endif + switch (er.what) + { + case mouseDown: + inev.modifiers |= down_modifier; + break; + case mouseUp: + inev.modifiers |= up_modifier; + break; + } + } + break; + + case inDrag: +#if TARGET_API_MAC_CARBON + case inProxyIcon: + if (IsWindowPathSelectClick (window_ptr, &er)) + { + WindowPathSelect (window_ptr, NULL, NULL); + break; + } + if (part_code == inProxyIcon + && (TrackWindowProxyDrag (window_ptr, er.where) + != errUserWantsToDragWindow)) + break; + DragWindow (window_ptr, er.where, NULL); +#else /* not TARGET_API_MAC_CARBON */ + DragWindow (window_ptr, er.where, &qd.screenBits.bounds); + /* Update the frame parameters. */ + { + struct frame *f = mac_window_to_frame (window_ptr); + + if (f && !f->async_iconified) + mac_handle_origin_change (f); + } +#endif /* not TARGET_API_MAC_CARBON */ + break; + + case inGoAway: + if (TrackGoAway (window_ptr, er.where)) + { + inev.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.frame_or_window, + mac_window_to_frame (window_ptr)); + } + break; + + /* window resize handling added --ben */ + case inGrow: + do_grow_window (window_ptr, &er); + break; + + /* window zoom handling added --ben */ + case inZoomIn: + case inZoomOut: + if (TrackBox (window_ptr, er.where, part_code)) + do_zoom_window (window_ptr, part_code); + break; + +#if USE_MAC_TOOLBAR + case inStructure: + { + OSStatus err; + HIViewRef ch; + + err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr), + eventRef, &ch); + /* This doesn't work on Mac OS X 10.2. */ + if (err == noErr) + HIViewClick (ch, eventRef); + } + break; +#endif /* USE_MAC_TOOLBAR */ + + default: + break; + } + } + break; + +#if !TARGET_API_MAC_CARBON + case updateEvt: + do_window_update ((WindowRef) er.message); + break; +#endif + + case osEvt: +#if TARGET_API_MAC_CARBON + if (SendEventToEventTarget (eventRef, toolbox_dispatcher) + != eventNotHandledErr) + break; +#endif + switch ((er.message >> 24) & 0x000000FF) + { +#if USE_MAC_TSM + case suspendResumeMessage: + if (er.message & resumeFlag) + mac_tsm_resume (); + else + mac_tsm_suspend (); + break; +#endif + + case mouseMovedMessage: +#if !TARGET_API_MAC_CARBON + SetRectRgn (mouse_region, er.where.h, er.where.v, + er.where.h + 1, er.where.v + 1); +#endif + previous_help_echo_string = help_echo_string; + help_echo_string = Qnil; + + if (dpyinfo->grabbed && last_mouse_frame + && FRAME_LIVE_P (last_mouse_frame)) + f = last_mouse_frame; + else + f = dpyinfo->x_focus_frame; + + if (dpyinfo->mouse_face_hidden) + { + dpyinfo->mouse_face_hidden = 0; + clear_mouse_face (dpyinfo); + } + + if (f) + { + WindowRef wp = FRAME_MAC_WINDOW (f); + Point mouse_pos; + + mouse_pos.h = (er.where.h + - (f->left_pos + + FRAME_OUTER_TO_INNER_DIFF_X (f))); + mouse_pos.v = (er.where.v + - (f->top_pos + + FRAME_OUTER_TO_INNER_DIFF_Y (f))); + if (dpyinfo->grabbed && tracked_scroll_bar) +#ifdef USE_TOOLKIT_SCROLL_BARS + x_scroll_bar_handle_drag (wp, tracked_scroll_bar, + mouse_pos, &inev); +#else /* not USE_TOOLKIT_SCROLL_BARS */ + x_scroll_bar_note_movement (tracked_scroll_bar, + mouse_pos.v + - XINT (tracked_scroll_bar->top), + er.when * (1000 / 60)); +#endif /* not USE_TOOLKIT_SCROLL_BARS */ + else + { + /* Generate SELECT_WINDOW_EVENTs when needed. */ + if (!NILP (Vmouse_autoselect_window)) + { + Lisp_Object window; + + window = window_from_coordinates (f, + mouse_pos.h, + mouse_pos.v, + 0, 0, 0, 0); + + /* Window will be selected only when it is + not selected now and last mouse movement + event was not in it. Minibuffer window + will be selected only when it is active. */ + if (WINDOWP (window) + && !EQ (window, last_window) + && !EQ (window, selected_window) + /* For click-to-focus window managers + create event iff we don't leave the + selected frame. */ + && (focus_follows_mouse + || (EQ (XWINDOW (window)->frame, + XWINDOW (selected_window)->frame)))) + { + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = window; + } + + last_window=window; + } + if (!note_mouse_movement (f, &mouse_pos)) + help_echo_string = previous_help_echo_string; +#if USE_MAC_TOOLBAR + else + mac_tool_bar_note_mouse_movement (f, eventRef); +#endif + } + } + + /* If the contents of the global variable + help_echo_string has changed, generate a + HELP_EVENT. */ + if (!NILP (help_echo_string) || !NILP (previous_help_echo_string)) + do_help = 1; + break; + } + break; + + case activateEvt: + { + WindowRef window_ptr = (WindowRef) er.message; + OSErr err; + ControlRef root_control; + + if (window_ptr == tip_window) + { + HideWindow (tip_window); + break; + } + + if (!is_emacs_window (window_ptr)) + goto OTHER; + + f = mac_window_to_frame (window_ptr); + + if ((er.modifiers & activeFlag) != 0) + { + /* A window has been activated */ + Point mouse_loc; + + err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control); + if (err == noErr) + ActivateControl (root_control); + + x_detect_focus_change (dpyinfo, &er, &inev); + + mouse_loc.h = (er.where.h + - (f->left_pos + + FRAME_OUTER_TO_INNER_DIFF_X (f))); + mouse_loc.v = (er.where.v + - (f->top_pos + + FRAME_OUTER_TO_INNER_DIFF_Y (f))); + /* Window-activated event counts as mouse movement, + so update things that depend on mouse position. */ + note_mouse_movement (f, &mouse_loc); + } + else + { + /* A window has been deactivated */ + err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control); + if (err == noErr) + DeactivateControl (root_control); + +#ifdef USE_TOOLKIT_SCROLL_BARS + if (dpyinfo->grabbed && tracked_scroll_bar) + { + struct input_event event; + + EVENT_INIT (event); + event.kind = NO_EVENT; + x_scroll_bar_handle_release (tracked_scroll_bar, &event); + if (event.kind != NO_EVENT) + { + event.timestamp = timestamp; + kbd_buffer_store_event_hold (&event, hold_quit); + count++; + } + } +#endif + dpyinfo->grabbed = 0; + + x_detect_focus_change (dpyinfo, &er, &inev); + + if (f == dpyinfo->mouse_face_mouse_frame) + { + /* If we move outside the frame, then we're + certainly no longer on any text in the + frame. */ + clear_mouse_face (dpyinfo); + dpyinfo->mouse_face_mouse_frame = 0; + } + + /* Generate a nil HELP_EVENT to cancel a help-echo. + Do it only if there's something to cancel. + Otherwise, the startup message is cleared when the + mouse leaves the frame. */ + if (any_help_event_p) + do_help = -1; + } + } + break; + + case keyDown: + case keyUp: + case autoKey: + ObscureCursor (); + + f = mac_focus_frame (dpyinfo); + XSETFRAME (inev.frame_or_window, f); + + /* If mouse-highlight is an integer, input clears out mouse + highlighting. */ + if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight) + && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window)) + { + clear_mouse_face (dpyinfo); + dpyinfo->mouse_face_hidden = 1; + } + + { + UInt32 modifiers = er.modifiers, mapped_modifiers; + UInt32 key_code = (er.message & keyCodeMask) >> 8; + +#ifdef MAC_OSX + GetEventParameter (eventRef, kEventParamKeyModifiers, + typeUInt32, NULL, + sizeof (UInt32), NULL, &modifiers); +#endif + mapped_modifiers = mac_mapped_modifiers (modifiers, key_code); + +#if TARGET_API_MAC_CARBON + if (!(mapped_modifiers + & ~(mac_pass_command_to_system ? cmdKey : 0) + & ~(mac_pass_control_to_system ? controlKey : 0))) + goto OTHER; + else +#endif + if (er.what != keyUp) + do_keystroke (er.what, er.message & charCodeMask, + key_code, modifiers, timestamp, &inev); + } + break; + + case kHighLevelEvent: + AEProcessAppleEvent (&er); + break; + + default: + OTHER: +#if TARGET_API_MAC_CARBON + { + OSStatus err; + + read_socket_inev = &inev; + err = SendEventToEventTarget (eventRef, toolbox_dispatcher); + read_socket_inev = NULL; + } +#endif + break; + } +#if TARGET_API_MAC_CARBON + ReleaseEvent (eventRef); +#endif + + if (inev.kind != NO_EVENT) + { + inev.timestamp = timestamp; + kbd_buffer_store_event_hold (&inev, hold_quit); + count++; + } + + if (do_help + && !(hold_quit && hold_quit->kind != NO_EVENT)) + { + Lisp_Object frame; + + if (f) + XSETFRAME (frame, f); + else + frame = Qnil; + + if (do_help > 0) + { + any_help_event_p = 1; + gen_help_event (help_echo_string, frame, help_echo_window, + help_echo_object, help_echo_pos); + } + else + { + help_echo_string = Qnil; + gen_help_event (Qnil, frame, Qnil, Qnil, 0); + } + count++; + } + } + + /* If the focus was just given to an autoraising frame, + raise it now. */ + /* ??? This ought to be able to handle more than one such frame. */ + if (pending_autoraise_frame) + { + x_raise_frame (pending_autoraise_frame); + pending_autoraise_frame = 0; + } + + if (mac_screen_config_changed) + { + mac_get_screen_info (dpyinfo); + mac_screen_config_changed = 0; + } + +#if !TARGET_API_MAC_CARBON + /* Check which frames are still visible. We do this here because + there doesn't seem to be any direct notification from the Window + Manager that the visibility of a window has changed (at least, + not in all cases). */ + { + Lisp_Object tail, frame; + + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + + /* The tooltip has been drawn already. Avoid the + SET_FRAME_GARBAGED in mac_handle_visibility_change. */ + if (EQ (frame, tip_frame)) + continue; + + if (FRAME_MAC_P (f)) + mac_handle_visibility_change (f); + } + } +#endif + + --handling_signal; + UNBLOCK_INPUT; + return count; +} + + +/*********************************************************************** + Busy cursor + ***********************************************************************/ + +#if TARGET_API_MAC_CARBON +/* Show the spinning progress indicator for the frame F. Create it if + it doesn't exist yet. */ + +void +mac_show_hourglass (f) + struct frame *f; +{ +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (f); +#endif + if (!f->output_data.mac->hourglass_control) + { + Window w = FRAME_MAC_WINDOW (f); + Rect r; + ControlRef c; + + GetWindowPortBounds (w, &r); + r.left = r.right - HOURGLASS_WIDTH; + r.bottom = r.top + HOURGLASS_HEIGHT; + if (CreateChasingArrowsControl (w, &r, &c) == noErr) + f->output_data.mac->hourglass_control = c; + } + + if (f->output_data.mac->hourglass_control) + ShowControl (f->output_data.mac->hourglass_control); +} + +/* Hide the spinning progress indicator for the frame F. Do nothing + it doesn't exist yet. */ + +void +mac_hide_hourglass (f) + struct frame *f; +{ + if (f->output_data.mac->hourglass_control) + { +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (f); +#endif + HideControl (f->output_data.mac->hourglass_control); + } +} + +/* Reposition the spinning progress indicator for the frame F. Do + nothing it doesn't exist yet. */ + +void +mac_reposition_hourglass (f) + struct frame *f; +{ + if (f->output_data.mac->hourglass_control) + { +#if USE_CG_DRAWING + mac_prepare_for_quickdraw (f); +#endif + MoveControl (f->output_data.mac->hourglass_control, + FRAME_PIXEL_WIDTH (f) - HOURGLASS_WIDTH, 0); + } +} +#endif /* TARGET_API_MAC_CARBON */ + + +/*********************************************************************** + File selection dialog + ***********************************************************************/ + +#if TARGET_API_MAC_CARBON +extern Lisp_Object Qfile_name_history; + +static pascal void mac_nav_event_callback P_ ((NavEventCallbackMessage, + NavCBRecPtr, void *)); + +/* The actual implementation of Fx_file_dialog. */ + +Lisp_Object +mac_file_dialog (prompt, dir, default_filename, mustmatch, only_dir_p) + Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p; +{ + Lisp_Object file = Qnil; + int count = SPECPDL_INDEX (); + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; + char filename[MAXPATHLEN]; + static NavEventUPP mac_nav_event_callbackUPP = NULL; + + check_mac (); + + GCPRO6 (prompt, dir, default_filename, mustmatch, file, only_dir_p); + CHECK_STRING (prompt); + CHECK_STRING (dir); + + /* Create the dialog with PROMPT as title, using DIR as initial + directory and using "*" as pattern. */ + dir = Fexpand_file_name (dir, Qnil); + + { + OSStatus status; + NavDialogCreationOptions options; + NavDialogRef dialogRef; + NavTypeListHandle fileTypes = NULL; + NavUserAction userAction; + CFStringRef message=NULL, saveName = NULL; + + BLOCK_INPUT; + /* No need for a callback function because we are modal */ + NavGetDefaultDialogCreationOptions(&options); + options.modality = kWindowModalityAppModal; + options.location.h = options.location.v = -1; + options.optionFlags = kNavDefaultNavDlogOptions; + options.optionFlags |= kNavAllFilesInPopup; /* All files allowed */ + options.optionFlags |= kNavSelectAllReadableItem; + options.optionFlags &= ~kNavAllowMultipleFiles; + if (!NILP(prompt)) + { + message = cfstring_create_with_string (prompt); + options.message = message; + } + /* Don't set the application, let it use default. + options.clientName = CFSTR ("Emacs"); + */ + + if (mac_nav_event_callbackUPP == NULL) + mac_nav_event_callbackUPP = NewNavEventUPP (mac_nav_event_callback); + + if (!NILP (only_dir_p)) + status = NavCreateChooseFolderDialog(&options, mac_nav_event_callbackUPP, + NULL, NULL, &dialogRef); + else if (NILP (mustmatch)) + { + /* This is a save dialog */ + options.optionFlags |= kNavDontConfirmReplacement; + options.actionButtonLabel = CFSTR ("Ok"); + options.windowTitle = CFSTR ("Enter name"); + + if (STRINGP (default_filename)) + { + Lisp_Object utf8 = ENCODE_UTF_8 (default_filename); + char *begPtr = SDATA(utf8); + char *filePtr = begPtr + SBYTES(utf8); + while (filePtr != begPtr && !IS_DIRECTORY_SEP(filePtr[-1])) + filePtr--; + saveName = cfstring_create_with_utf8_cstring (filePtr); + options.saveFileName = saveName; + options.optionFlags |= kNavSelectDefaultLocation; + } + status = NavCreatePutFileDialog(&options, + 'TEXT', kNavGenericSignature, + mac_nav_event_callbackUPP, NULL, + &dialogRef); + } + else + { + /* This is an open dialog*/ + status = NavCreateChooseFileDialog(&options, fileTypes, + mac_nav_event_callbackUPP, NULL, + NULL, NULL, &dialogRef); + } + + /* Set the default location and continue*/ + if (status == noErr) + { + Lisp_Object encoded_dir = ENCODE_FILE (dir); + AEDesc defLocAed; + + status = AECreateDesc (TYPE_FILE_NAME, SDATA (encoded_dir), + SBYTES (encoded_dir), &defLocAed); + if (status == noErr) + { + NavCustomControl(dialogRef, kNavCtlSetLocation, (void*) &defLocAed); + AEDisposeDesc(&defLocAed); + } + status = NavDialogRun(dialogRef); + } + + if (saveName) CFRelease(saveName); + if (message) CFRelease(message); + + if (status == noErr) { + userAction = NavDialogGetUserAction(dialogRef); + switch (userAction) + { + case kNavUserActionNone: + case kNavUserActionCancel: + break; /* Treat cancel like C-g */ + case kNavUserActionOpen: + case kNavUserActionChoose: + case kNavUserActionSaveAs: + { + NavReplyRecord reply; + Size len; + + status = NavDialogGetReply(dialogRef, &reply); + if (status != noErr) + break; + status = AEGetNthPtr (&reply.selection, 1, TYPE_FILE_NAME, + NULL, NULL, filename, + sizeof (filename) - 1, &len); + if (status == noErr) + { + len = min (len, sizeof (filename) - 1); + filename[len] = '\0'; + if (reply.saveFileName) + { + /* If it was a saved file, we need to add the file name */ + if (len && len < sizeof (filename) - 1 + && filename[len-1] != '/') + filename[len++] = '/'; + CFStringGetCString(reply.saveFileName, filename+len, + sizeof (filename) - len, +#ifdef MAC_OSX + kCFStringEncodingUTF8 +#else + CFStringGetSystemEncoding () +#endif + ); + } + file = DECODE_FILE (make_unibyte_string (filename, + strlen (filename))); + } + NavDisposeReply(&reply); + } + break; + } + NavDialogDispose(dialogRef); + UNBLOCK_INPUT; + } + else { + UNBLOCK_INPUT; + /* Fall back on minibuffer if there was a problem */ + file = Fcompleting_read (prompt, intern ("read-file-name-internal"), + dir, mustmatch, dir, Qfile_name_history, + default_filename, Qnil); + } + } + + UNGCPRO; + + /* Make "Cancel" equivalent to C-g. */ + if (NILP (file)) + Fsignal (Qquit, Qnil); + + return unbind_to (count, file); +} + +/* Need to register some event callback function for enabling drag and + drop in Navigation Service dialogs. */ +static pascal void +mac_nav_event_callback (selector, parms, data) + NavEventCallbackMessage selector; + NavCBRecPtr parms; + void *data; +{ +} +#endif + + +/************************************************************************ + Menu + ************************************************************************/ + +#if !TARGET_API_MAC_CARBON +#include +#include +#include +#include +#include +#include +#include +#include +#if defined (__MRC__) || (__MSL__ >= 0x6000) +#include +#endif +#endif /* not TARGET_API_MAC_CARBON */ + +extern int menu_item_selection; +extern int popup_activated_flag; +extern int name_is_separator P_ ((const char *)); +extern void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object, + void *)); +extern void set_frame_menubar P_ ((FRAME_PTR, int, int)); + +enum mac_menu_kind { /* Menu ID range */ + MAC_MENU_APPLE, /* 0 (Reserved by Apple) */ + MAC_MENU_MENU_BAR, /* 1 .. 233 */ + MAC_MENU_M_APPLE, /* 234 (== M_APPLE) */ + MAC_MENU_POPUP, /* 235 */ + MAC_MENU_DRIVER, /* 236 .. 255 (Reserved) */ + MAC_MENU_MENU_BAR_SUB, /* 256 .. 16383 */ + MAC_MENU_POPUP_SUB, /* 16384 .. 32767 */ + MAC_MENU_END /* 32768 */ +}; + +static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768}; + +static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int)); +static void dispose_menus P_ ((enum mac_menu_kind, int)); + +#if !TARGET_API_MAC_CARBON +static void +do_apple_menu (SInt16 menu_item) +{ + Str255 item_name; + SInt16 da_driver_refnum; + + if (menu_item == I_ABOUT) + NoteAlert (ABOUT_ALERT_ID, NULL); + else + { + GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name); + da_driver_refnum = OpenDeskAcc (item_name); + } +} +#endif /* !TARGET_API_MAC_CARBON */ + +/* Activate the menu bar of frame F. + This is called from keyboard.c when it gets the + MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue. + + To activate the menu bar, we use the button-press event location + that was saved in saved_menu_event_location. + + But first we recompute the menu bar contents (the whole tree). + + The reason for saving the button event until here, instead of + passing it to the toolkit right away, is that we can safely + execute Lisp code. */ + +void +x_activate_menubar (f) + FRAME_PTR f; +{ + SInt32 menu_choice; + SInt16 menu_id, menu_item; + extern Point saved_menu_event_location; + + set_frame_menubar (f, 0, 1); + BLOCK_INPUT; + + popup_activated_flag = 1; + menu_choice = MenuSelect (saved_menu_event_location); + popup_activated_flag = 0; + menu_id = HiWord (menu_choice); + menu_item = LoWord (menu_choice); + +#if !TARGET_API_MAC_CARBON + if (menu_id == min_menu_id[MAC_MENU_M_APPLE]) + do_apple_menu (menu_item); + else +#endif + if (menu_id) + { + MenuRef menu = GetMenuRef (menu_id); + + if (menu) + { + UInt32 refcon; + + GetMenuItemRefCon (menu, menu_item, &refcon); + find_and_call_menu_selection (f, f->menu_bar_items_used, + f->menu_bar_vector, (void *) refcon); + } + } + + HiliteMenu (0); + + UNBLOCK_INPUT; +} + +#if TARGET_API_MAC_CARBON +extern Lisp_Object Vshow_help_function; + +static Lisp_Object +restore_show_help_function (old_show_help_function) + Lisp_Object old_show_help_function; +{ + Vshow_help_function = old_show_help_function; + + return Qnil; +} + +static pascal OSStatus +menu_target_item_handler (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + OSStatus err; + MenuRef menu; + MenuItemIndex menu_item; + Lisp_Object help; + GrafPtr port; + int specpdl_count = SPECPDL_INDEX (); + + /* Don't be bothered with the overflowed toolbar items menu. */ + if (!popup_activated ()) + return eventNotHandledErr; + + err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef, + NULL, sizeof (MenuRef), NULL, &menu); + if (err == noErr) + err = GetEventParameter (event, kEventParamMenuItemIndex, + typeMenuItemIndex, NULL, + sizeof (MenuItemIndex), NULL, &menu_item); + if (err == noErr) + err = GetMenuItemProperty (menu, menu_item, + MAC_EMACS_CREATOR_CODE, 'help', + sizeof (Lisp_Object), NULL, &help); + if (err != noErr) + help = Qnil; + + /* Temporarily bind Vshow_help_function to Qnil because we don't + want tooltips during menu tracking. */ + record_unwind_protect (restore_show_help_function, Vshow_help_function); + Vshow_help_function = Qnil; + GetPort (&port); + show_help_echo (help, Qnil, Qnil, Qnil, 1); + SetPort (port); + unbind_to (specpdl_count, Qnil); + + return err == noErr ? noErr : eventNotHandledErr; +} + +/* Showing help echo string during menu tracking. */ + +static OSStatus +install_menu_target_item_handler () +{ + static const EventTypeSpec specs[] = + {{kEventClassMenu, kEventMenuTargetItem}}; + + return InstallApplicationEventHandler (NewEventHandlerUPP + (menu_target_item_handler), + GetEventTypeCount (specs), + specs, NULL, NULL); +} +#endif /* TARGET_API_MAC_CARBON */ + +/* Event handler function that pops down a menu on C-g. We can only pop + down menus if CancelMenuTracking is present (OSX 10.3 or later). */ + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 +static pascal OSStatus +menu_quit_handler (nextHandler, theEvent, userData) + EventHandlerCallRef nextHandler; + EventRef theEvent; + void* userData; +{ + OSStatus err; + UInt32 keyCode; + UInt32 keyModifiers; + + err = GetEventParameter (theEvent, kEventParamKeyCode, + typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); + + if (err == noErr) + err = GetEventParameter (theEvent, kEventParamKeyModifiers, + typeUInt32, NULL, sizeof(UInt32), + NULL, &keyModifiers); + + if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode)) + { + MenuRef menu = userData != 0 + ? (MenuRef)userData : AcquireRootMenu (); + + CancelMenuTracking (menu, true, 0); + if (!userData) ReleaseMenu (menu); + return noErr; + } + + return CallNextEventHandler (nextHandler, theEvent); +} +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */ + +/* Add event handler to all menus that belong to KIND so we can detect + C-g. ROOT_MENU is the root menu of the tracking session to dismiss + when C-g is detected. NULL means the menu bar. If + CancelMenuTracking isn't available, do nothing. */ + +static void +install_menu_quit_handler (kind, root_menu) + enum mac_menu_kind kind; + MenuRef root_menu; +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 + static const EventTypeSpec typesList[] = + {{kEventClassKeyboard, kEventRawKeyDown}}; + int id; + +#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020 + if (CancelMenuTracking == NULL) + return; +#endif + for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++) + { + MenuRef menu = GetMenuRef (id); + + if (menu == NULL) + break; + InstallMenuEventHandler (menu, menu_quit_handler, + GetEventTypeCount (typesList), + typesList, root_menu, NULL); + } +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */ +} + +static Lisp_Object +pop_down_menu (arg) + Lisp_Object arg; +{ + struct Lisp_Save_Value *p = XSAVE_VALUE (arg); + FRAME_PTR f = p->pointer; + MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]); + + BLOCK_INPUT; + + /* Must reset this manually because the button release event is not + passed to Emacs event loop. */ + FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0; + + /* delete all menus */ + dispose_menus (MAC_MENU_POPUP_SUB, 0); + DeleteMenu (min_menu_id[MAC_MENU_POPUP]); + DisposeMenu (menu); + + UNBLOCK_INPUT; + + return Qnil; +} + +/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop + until the menu pops down. Return the selection. */ + +void +create_and_show_popup_menu (f, first_wv, x, y, for_click) + FRAME_PTR f; + widget_value *first_wv; + int x; + int y; + int for_click; +{ + int result = 0; + MenuRef menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p"); + int menu_item_choice; + int specpdl_count = SPECPDL_INDEX (); + + InsertMenu (menu, -1); + fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB, + min_menu_id[MAC_MENU_POPUP_SUB]); + + /* Add event handler so we can detect C-g. */ + install_menu_quit_handler (MAC_MENU_POPUP, menu); + install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu); + + record_unwind_protect (pop_down_menu, make_save_value (f, 0)); + + /* Adjust coordinates to be root-window-relative. */ + x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); + y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); + + /* Display the menu. */ + popup_activated_flag = 1; + menu_item_choice = PopUpMenuSelect (menu, y, x, 0); + popup_activated_flag = 0; + + /* Get the refcon to find the correct item */ + if (menu_item_choice) + { + MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice)); + + if (sel_menu) + GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice), + (UInt32 *) &result); + } + + unbind_to (specpdl_count, Qnil); + + menu_item_selection = result; +} + +static void +add_menu_item (menu, pos, wv) + MenuRef menu; + int pos; + widget_value *wv; +{ +#if TARGET_API_MAC_CARBON + CFStringRef item_name; +#else + Str255 item_name; +#endif + + if (name_is_separator (wv->name)) + AppendMenu (menu, "\p-"); + else + { + AppendMenu (menu, "\pX"); + +#if TARGET_API_MAC_CARBON + item_name = cfstring_create_with_utf8_cstring (wv->name); + + if (wv->key != NULL) + { + CFStringRef name, key; + + name = item_name; + key = cfstring_create_with_utf8_cstring (wv->key); + item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"), + name, key); + CFRelease (name); + CFRelease (key); + } + + SetMenuItemTextWithCFString (menu, pos, item_name); + CFRelease (item_name); + + if (wv->enabled) + EnableMenuItem (menu, pos); + else + DisableMenuItem (menu, pos); + + if (STRINGP (wv->help)) + SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help', + sizeof (Lisp_Object), &wv->help); +#else /* ! TARGET_API_MAC_CARBON */ + item_name[sizeof (item_name) - 1] = '\0'; + strncpy (item_name, wv->name, sizeof (item_name) - 1); + if (wv->key != NULL) + { + int len = strlen (item_name); + + strncpy (item_name + len, " ", sizeof (item_name) - 1 - len); + len = strlen (item_name); + strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len); + } + c2pstr (item_name); + SetMenuItemText (menu, pos, item_name); + + if (wv->enabled) + EnableItem (menu, pos); + else + DisableItem (menu, pos); +#endif /* ! TARGET_API_MAC_CARBON */ + + /* Draw radio buttons and tickboxes. */ + if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE + || wv->button_type == BUTTON_TYPE_RADIO)) + SetItemMark (menu, pos, checkMark); + else + SetItemMark (menu, pos, noMark); + + SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data); + } +} + +/* Construct native Mac OS menu based on widget_value tree. */ + +static int +fill_menu (menu, wv, kind, submenu_id) + MenuRef menu; + widget_value *wv; + enum mac_menu_kind kind; + int submenu_id; +{ + int pos; + + for (pos = 1; wv != NULL; wv = wv->next, pos++) + { + add_menu_item (menu, pos, wv); + if (wv->contents && submenu_id < min_menu_id[kind + 1]) + { + MenuRef submenu = NewMenu (submenu_id, "\pX"); + + InsertMenu (submenu, -1); +#if TARGET_API_MAC_CARBON + SetMenuItemHierarchicalMenu (menu, pos, submenu); +#else + SetMenuItemHierarchicalID (menu, pos, submenu_id); +#endif + submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1); + } + } + + return submenu_id; +} + +/* Fill menu bar with the items defined by WV. If DEEP_P, consider + the entire menu trees we supply, rather than just the menu bar item + names. */ + +void +mac_fill_menubar (wv, deep_p) + widget_value *wv; + int deep_p; +{ + int id, submenu_id; +#if !TARGET_API_MAC_CARBON + int title_changed_p = 0; +#endif + + /* Clean up the menu bar when filled by the entire menu trees. */ + if (deep_p) + { + dispose_menus (MAC_MENU_MENU_BAR, 0); + dispose_menus (MAC_MENU_MENU_BAR_SUB, 0); +#if !TARGET_API_MAC_CARBON + title_changed_p = 1; +#endif + } + + /* Fill menu bar titles and submenus. Reuse the existing menu bar + titles as much as possible to minimize redraw (if !deep_p). */ + submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB]; + for (id = min_menu_id[MAC_MENU_MENU_BAR]; + wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1]; + wv = wv->next, id++) + { + OSStatus err = noErr; + MenuRef menu; +#if TARGET_API_MAC_CARBON + CFStringRef title; + + title = CFStringCreateWithCString (NULL, wv->name, + kCFStringEncodingMacRoman); +#else + Str255 title; + + strncpy (title, wv->name, 255); + title[255] = '\0'; + c2pstr (title); +#endif + + menu = GetMenuRef (id); + if (menu) + { +#if TARGET_API_MAC_CARBON + CFStringRef old_title; + + err = CopyMenuTitleAsCFString (menu, &old_title); + if (err == noErr) + { + if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo) + { +#ifdef MAC_OSX + if (id + 1 == min_menu_id[MAC_MENU_MENU_BAR + 1] + || GetMenuRef (id + 1) == NULL) + { + /* This is a workaround for Mac OS X 10.5 where + just calling SetMenuTitleWithCFString fails + to change the title of the last (Help) menu + in the menu bar. */ + DeleteMenu (id); + DisposeMenu (menu); + menu = NULL; + } + else +#endif /* MAC_OSX */ + err = SetMenuTitleWithCFString (menu, title); + } + CFRelease (old_title); + } + else + err = SetMenuTitleWithCFString (menu, title); +#else /* !TARGET_API_MAC_CARBON */ + if (!EqualString (title, (*menu)->menuData, false, false)) + { + DeleteMenu (id); + DisposeMenu (menu); + menu = NewMenu (id, title); + InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0); + title_changed_p = 1; + } +#endif /* !TARGET_API_MAC_CARBON */ + } + + if (!menu) + { +#if TARGET_API_MAC_CARBON + err = CreateNewMenu (id, 0, &menu); + if (err == noErr) + err = SetMenuTitleWithCFString (menu, title); +#else + menu = NewMenu (id, title); +#endif + if (err == noErr) + { + InsertMenu (menu, 0); +#if !TARGET_API_MAC_CARBON + title_changed_p = 1; +#endif + } + } +#if TARGET_API_MAC_CARBON + CFRelease (title); +#endif + + if (err == noErr) + if (wv->contents) + submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB, + submenu_id); + } + + if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id)) + { + dispose_menus (MAC_MENU_MENU_BAR, id); +#if !TARGET_API_MAC_CARBON + title_changed_p = 1; +#endif + } + +#if !TARGET_API_MAC_CARBON + if (title_changed_p) + InvalMenuBar (); +#endif + + /* Add event handler so we can detect C-g. */ + install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL); + install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL); +} + +/* Dispose of menus that belong to KIND, and remove them from the menu + list. ID is the lower bound of menu IDs that will be processed. */ + +static void +dispose_menus (kind, id) + enum mac_menu_kind kind; + int id; +{ + for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++) + { + MenuRef menu = GetMenuRef (id); + + if (menu == NULL) + break; + DeleteMenu (id); + DisposeMenu (menu); + } +} + +static void +init_menu_bar () +{ +#ifdef MAC_OSX + OSStatus err; + MenuRef menu; + MenuItemIndex menu_index; + + err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1, + &menu, &menu_index); + if (err == noErr) + SetMenuItemCommandKey (menu, menu_index, false, 0); + EnableMenuCommand (NULL, kHICommandPreferences); + err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1, + &menu, &menu_index); + if (err == noErr) + { + SetMenuItemCommandKey (menu, menu_index, false, 0); + InsertMenuItemTextWithCFString (menu, NULL, + 0, kMenuItemAttrSeparator, 0); + InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"), + 0, 0, kHICommandAbout); + } +#else /* !MAC_OSX */ +#if TARGET_API_MAC_CARBON + SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout); +#endif +#endif +} + + +/*********************************************************************** + Popup Dialog + ***********************************************************************/ + +#if TARGET_API_MAC_CARBON +#define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0' +#define DIALOG_BUTTON_COMMAND_ID_P(id) \ + (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET) +#define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \ + ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET) +#define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \ + ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET) + +extern EMACS_TIME timer_check P_ ((int)); +static int quit_dialog_event_loop; + +static pascal OSStatus +mac_handle_dialog_event (next_handler, event, data) + EventHandlerCallRef next_handler; + EventRef event; + void *data; +{ + OSStatus err, result = eventNotHandledErr; + WindowRef window = (WindowRef) data; + + switch (GetEventClass (event)) + { + case kEventClassCommand: + { + HICommand command; + + err = GetEventParameter (event, kEventParamDirectObject, + typeHICommand, NULL, sizeof (HICommand), + NULL, &command); + if (err == noErr) + if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID)) + { + SetWRefCon (window, command.commandID); + quit_dialog_event_loop = 1; + break; + } + + result = CallNextEventHandler (next_handler, event); + } + break; + + case kEventClassKeyboard: + { + OSStatus result; + char char_code; + + result = CallNextEventHandler (next_handler, event); + if (result != eventNotHandledErr) + break; + + err = GetEventParameter (event, kEventParamKeyMacCharCodes, + typeChar, NULL, sizeof (char), + NULL, &char_code); + if (err == noErr) + switch (char_code) + { + case kEscapeCharCode: + quit_dialog_event_loop = 1; + break; + + default: + { + UInt32 modifiers, key_code; + + err = GetEventParameter (event, kEventParamKeyModifiers, + typeUInt32, NULL, sizeof (UInt32), + NULL, &modifiers); + if (err == noErr) + err = GetEventParameter (event, kEventParamKeyCode, + typeUInt32, NULL, sizeof (UInt32), + NULL, &key_code); + if (err == noErr) + if (mac_quit_char_key_p (modifiers, key_code)) + quit_dialog_event_loop = 1; + } + break; + } + } + break; + + default: + abort (); + } + + if (quit_dialog_event_loop) + { + err = QuitEventLoop (GetCurrentEventLoop ()); + if (err == noErr) + result = noErr; + } + + return result; +} + +static OSStatus +install_dialog_event_handler (window) + WindowRef window; +{ + static const EventTypeSpec specs[] = + {{kEventClassCommand, kEventCommandProcess}, + {kEventClassKeyboard, kEventRawKeyDown}}; + static EventHandlerUPP handle_dialog_eventUPP = NULL; + + if (handle_dialog_eventUPP == NULL) + handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event); + return InstallWindowEventHandler (window, handle_dialog_eventUPP, + GetEventTypeCount (specs), specs, + window, NULL); +} + +static Lisp_Object +pop_down_dialog (arg) + Lisp_Object arg; +{ + struct Lisp_Save_Value *p = XSAVE_VALUE (arg); + WindowRef window = p->pointer; + + BLOCK_INPUT; + + if (popup_activated_flag) + EndAppModalStateForWindow (window); + DisposeWindow (window); + popup_activated_flag = 0; + + UNBLOCK_INPUT; + + return Qnil; +} + +/* Pop up the dialog for frame F defined by FIRST_WV and loop until the + dialog pops down. + menu_item_selection will be set to the selection. */ + +void +create_and_show_dialog (f, first_wv) + FRAME_PTR f; + widget_value *first_wv; +{ + OSStatus err; + char *dialog_name, *message; + int nb_buttons, first_group_count, i, result = 0; + widget_value *wv; + short buttons_height, text_height, inner_width, inner_height; + Rect empty_rect, *rects; + WindowRef window = NULL; + ControlRef *buttons, default_button = NULL, text; + int specpdl_count = SPECPDL_INDEX (); + + dialog_name = first_wv->name; + nb_buttons = dialog_name[1] - '0'; + first_group_count = nb_buttons - (dialog_name[4] - '0'); + + wv = first_wv->contents; + message = wv->value; + + wv = wv->next; + SetRect (&empty_rect, 0, 0, 0, 0); + + /* Create dialog window. */ + err = CreateNewWindow (kMovableModalWindowClass, + kWindowStandardHandlerAttribute, + &empty_rect, &window); + if (err == noErr) + { + record_unwind_protect (pop_down_dialog, make_save_value (window, 0)); + err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground, + true); + } + if (err == noErr) + err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q' + ? CFSTR ("Question") + : CFSTR ("Information"))); + + /* Create button controls and measure their optimal bounds. */ + if (err == noErr) + { + buttons = alloca (sizeof (ControlRef) * nb_buttons); + rects = alloca (sizeof (Rect) * nb_buttons); + for (i = 0; i < nb_buttons; i++) + { + CFStringRef label = cfstring_create_with_utf8_cstring (wv->value); + + if (label == NULL) + err = memFullErr; + else + { + err = CreatePushButtonControl (window, &empty_rect, + label, &buttons[i]); + CFRelease (label); + } + if (err == noErr) + { + if (!wv->enabled) + { +#ifdef MAC_OSX + err = DisableControl (buttons[i]); +#else + err = DeactivateControl (buttons[i]); +#endif + } + else if (default_button == NULL) + default_button = buttons[i]; + } + if (err == noErr) + { + SInt16 unused; + + rects[i] = empty_rect; + err = GetBestControlRect (buttons[i], &rects[i], &unused); + } + if (err == noErr) + { + UInt32 command_id; + + OffsetRect (&rects[i], -rects[i].left, -rects[i].top); + if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH) + rects[i].right = DIALOG_BUTTON_MIN_WIDTH; + else if (rects[i].right > DIALOG_MAX_INNER_WIDTH) + rects[i].right = DIALOG_MAX_INNER_WIDTH; + + command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data); + err = SetControlCommandID (buttons[i], command_id); + } + if (err != noErr) + break; + wv = wv->next; + } + } + + /* Layout buttons. rects[i] is set relative to the bottom-right + corner of the inner box. */ + if (err == noErr) + { + short bottom, right, max_height, left_align_shift; + + inner_width = DIALOG_MIN_INNER_WIDTH; + bottom = right = max_height = 0; + for (i = 0; i < nb_buttons; i++) + { + if (right - rects[i].right < - inner_width) + { + if (i != first_group_count + && right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH) + inner_width = - (right - rects[i].right); + else + { + bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE; + right = max_height = 0; + } + } + if (max_height < rects[i].bottom) + max_height = rects[i].bottom; + OffsetRect (&rects[i], right - rects[i].right, + bottom - rects[i].bottom); + right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE; + if (i == first_group_count - 1) + right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE; + } + buttons_height = - (bottom - max_height); + + left_align_shift = - (inner_width + rects[nb_buttons - 1].left); + for (i = nb_buttons - 1; i >= first_group_count; i--) + { + if (bottom != rects[i].bottom) + { + left_align_shift = - (inner_width + rects[i].left); + bottom = rects[i].bottom; + } + OffsetRect (&rects[i], left_align_shift, 0); + } + } + + /* Create a static text control and measure its bounds. */ + if (err == noErr) + { + CFStringRef message_string; + Rect bounds; + + message_string = cfstring_create_with_utf8_cstring (message); + if (message_string == NULL) + err = memFullErr; + else + { + ControlFontStyleRec text_style; + + text_style.flags = 0; + SetRect (&bounds, 0, 0, inner_width, 0); + err = CreateStaticTextControl (window, &bounds, message_string, + &text_style, &text); + CFRelease (message_string); + } + if (err == noErr) + { + SInt16 unused; + + bounds = empty_rect; + err = GetBestControlRect (text, &bounds, &unused); + } + if (err == noErr) + { + text_height = bounds.bottom - bounds.top; + if (text_height < DIALOG_TEXT_MIN_HEIGHT) + text_height = DIALOG_TEXT_MIN_HEIGHT; + } + } + + /* Place buttons. */ + if (err == noErr) + { + inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE + + buttons_height); + + for (i = 0; i < nb_buttons; i++) + { + OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width, + DIALOG_TOP_MARGIN + inner_height); + SetControlBounds (buttons[i], &rects[i]); + } + } + + /* Place text. */ + if (err == noErr) + { + Rect bounds; + + SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN, + DIALOG_LEFT_MARGIN + inner_width, + DIALOG_TOP_MARGIN + text_height); + SetControlBounds (text, &bounds); + } + + /* Create the application icon at the upper-left corner. */ + if (err == noErr) + { + ControlButtonContentInfo content; + ControlRef icon; + static const ProcessSerialNumber psn = {0, kCurrentProcess}; +#ifdef MAC_OSX + FSRef app_location; +#else + ProcessInfoRec pinfo; + FSSpec app_spec; +#endif + SInt16 unused; + + content.contentType = kControlContentIconRef; +#ifdef MAC_OSX + err = GetProcessBundleLocation (&psn, &app_location); + if (err == noErr) + err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL, + kIconServicesNormalUsageFlag, + &content.u.iconRef, &unused); +#else + bzero (&pinfo, sizeof (ProcessInfoRec)); + pinfo.processInfoLength = sizeof (ProcessInfoRec); + pinfo.processAppSpec = &app_spec; + err = GetProcessInformation (&psn, &pinfo); + if (err == noErr) + err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused); +#endif + if (err == noErr) + { + Rect bounds; + + SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN, + DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH, + DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT); + err = CreateIconControl (window, &bounds, &content, true, &icon); + ReleaseIconRef (content.u.iconRef); + } + } + + /* Show the dialog window and run event loop. */ + if (err == noErr) + if (default_button) + err = SetWindowDefaultButton (window, default_button); + if (err == noErr) + err = install_dialog_event_handler (window); + if (err == noErr) + { + SizeWindow (window, + DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN, + DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN, + true); + err = RepositionWindow (window, FRAME_MAC_WINDOW (f), + kWindowAlertPositionOnParentWindow); + } + if (err == noErr) + { + SetWRefCon (window, 0); + ShowWindow (window); + BringToFront (window); + popup_activated_flag = 1; + err = BeginAppModalStateForWindow (window); + } + if (err == noErr) + { + EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget (); + + quit_dialog_event_loop = 0; + while (1) + { + EMACS_TIME next_time = timer_check (1); + long secs = EMACS_SECS (next_time); + long usecs = EMACS_USECS (next_time); + EventTimeout timeout; + EventRef event; + + if (secs < 0 || (secs == 0 && usecs == 0)) + { + /* Sometimes timer_check returns -1 (no timers) even if + there are timers. So do a timeout anyway. */ + secs = 1; + usecs = 0; + } + + timeout = (secs * kEventDurationSecond + + usecs * kEventDurationMicrosecond); + err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue, + &event); + if (err == noErr) + { + SendEventToEventTarget (event, toolbox_dispatcher); + ReleaseEvent (event); + } +#if 0 /* defined (MAC_OSX) */ + else if (err != eventLoopTimedOutErr) + { + if (err == eventLoopQuitErr) + err = noErr; + break; + } +#else + /* The return value of ReceiveNextEvent seems to be + unreliable. Use our own global variable instead. */ + if (quit_dialog_event_loop) + { + err = noErr; + break; + } +#endif + } + } + if (err == noErr) + { + UInt32 command_id = GetWRefCon (window); + + if (DIALOG_BUTTON_COMMAND_ID_P (command_id)) + result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id); + } + + unbind_to (specpdl_count, Qnil); + + menu_item_selection = result; +} +#else /* not TARGET_API_MAC_CARBON */ +#define DIALOG_WINDOW_RESOURCE 130 + +int +mac_dialog (widget_value *wv) +{ + char *dialog_name; + char *prompt; + char **button_labels; + UInt32 *ref_cons; + int nb_buttons; + int left_count; + int i; + int dialog_width; + Rect rect; + WindowRef window_ptr; + ControlRef ch; + int left; + EventRecord event_record; + SInt16 part_code; + int control_part_code; + Point mouse; + + dialog_name = wv->name; + nb_buttons = dialog_name[1] - '0'; + left_count = nb_buttons - (dialog_name[4] - '0'); + button_labels = (char **) alloca (sizeof (char *) * nb_buttons); + ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons); + + wv = wv->contents; + prompt = (char *) alloca (strlen (wv->value) + 1); + strcpy (prompt, wv->value); + c2pstr (prompt); + + wv = wv->next; + for (i = 0; i < nb_buttons; i++) + { + button_labels[i] = wv->value; + button_labels[i] = (char *) alloca (strlen (wv->value) + 1); + strcpy (button_labels[i], wv->value); + c2pstr (button_labels[i]); + ref_cons[i] = (UInt32) wv->call_data; + wv = wv->next; + } + + window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1); + + SetPortWindowPort (window_ptr); + + TextFont (0); + /* Left and right margins in the dialog are 13 pixels each.*/ + dialog_width = 14; + /* Calculate width of dialog box: 8 pixels on each side of the text + label in each button, 12 pixels between buttons. */ + for (i = 0; i < nb_buttons; i++) + dialog_width += StringWidth (button_labels[i]) + 16 + 12; + + if (left_count != 0 && nb_buttons - left_count != 0) + dialog_width += 12; + + dialog_width = max (dialog_width, StringWidth (prompt) + 26); + + SizeWindow (window_ptr, dialog_width, 78, 0); + ShowWindow (window_ptr); + + SetPortWindowPort (window_ptr); + + TextFont (0); + + MoveTo (13, 29); + DrawString (prompt); + + left = 13; + for (i = 0; i < nb_buttons; i++) + { + int button_width = StringWidth (button_labels[i]) + 16; + SetRect (&rect, left, 45, left + button_width, 65); + ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0, + kControlPushButtonProc, ref_cons[i]); + left += button_width + 12; + if (i == left_count - 1) + left += 12; + } + + i = 0; + while (!i) + { + if (WaitNextEvent (mDownMask, &event_record, 10, NULL)) + if (event_record.what == mouseDown) + { + part_code = FindWindow (event_record.where, &window_ptr); + if (part_code == inContent) + { + mouse = event_record.where; + GlobalToLocal (&mouse); + control_part_code = FindControl (mouse, window_ptr, &ch); + if (control_part_code == kControlButtonPart) + if (TrackControl (ch, mouse, NULL)) + i = GetControlReference (ch); + } + } + } + + DisposeWindow (window_ptr); + + return i; +} +#endif /* not TARGET_API_MAC_CARBON */ + + +/*********************************************************************** + Selection support +***********************************************************************/ + +#if !TARGET_API_MAC_CARBON +#include +#include +#endif + +extern Lisp_Object Vselection_converter_alist; +extern Lisp_Object Qmac_scrap_name, Qmac_ostype; + +static ScrapFlavorType get_flavor_type_from_symbol P_ ((Lisp_Object, + Selection)); + +/* Get a reference to the selection corresponding to the symbol SYM. + The reference is set to *SEL, and it becomes NULL if there's no + corresponding selection. Clear the selection if CLEAR_P is + non-zero. */ + +OSStatus +mac_get_selection_from_symbol (sym, clear_p, sel) + Lisp_Object sym; + int clear_p; + Selection *sel; +{ + OSStatus err = noErr; + Lisp_Object str = Fget (sym, Qmac_scrap_name); + + if (!STRINGP (str)) + *sel = NULL; + else + { +#if TARGET_API_MAC_CARBON +#ifdef MAC_OSX + CFStringRef scrap_name = cfstring_create_with_string (str); + OptionBits options = (clear_p ? kScrapClearNamedScrap + : kScrapGetNamedScrap); + + err = GetScrapByName (scrap_name, options, sel); + CFRelease (scrap_name); +#else /* !MAC_OSX */ + if (clear_p) + err = ClearCurrentScrap (); + if (err == noErr) + err = GetCurrentScrap (sel); +#endif /* !MAC_OSX */ +#else /* !TARGET_API_MAC_CARBON */ + if (clear_p) + err = ZeroScrap (); + if (err == noErr) + *sel = 1; +#endif /* !TARGET_API_MAC_CARBON */ + } + + return err; +} + +/* Get a scrap flavor type from the symbol SYM. Return 0 if no + corresponding flavor type. If SEL is non-zero, the return value is + non-zero only when the SEL has the flavor type. */ + +static ScrapFlavorType +get_flavor_type_from_symbol (sym, sel) + Lisp_Object sym; + Selection sel; +{ + Lisp_Object str = Fget (sym, Qmac_ostype); + ScrapFlavorType flavor_type; + + if (STRINGP (str) && SBYTES (str) == 4) + flavor_type = EndianU32_BtoN (*((UInt32 *) SDATA (str))); + else + flavor_type = 0; + + if (flavor_type && sel) + { +#if TARGET_API_MAC_CARBON + OSStatus err; + ScrapFlavorFlags flags; + + err = GetScrapFlavorFlags (sel, flavor_type, &flags); + if (err != noErr) + flavor_type = 0; +#else /* !TARGET_API_MAC_CARBON */ + SInt32 size, offset; + + size = GetScrap (NULL, flavor_type, &offset); + if (size < 0) + flavor_type = 0; +#endif /* !TARGET_API_MAC_CARBON */ + } + + return flavor_type; +} + +/* Check if the symbol SYM has a corresponding selection target type. */ + +int +mac_valid_selection_target_p (sym) + Lisp_Object sym; +{ + return get_flavor_type_from_symbol (sym, 0) != 0; +} + +/* Clear the selection whose reference is *SEL. */ + +OSStatus +mac_clear_selection (sel) + Selection *sel; +{ +#if TARGET_API_MAC_CARBON +#ifdef MAC_OSX + return ClearScrap (sel); +#else + OSStatus err; + + err = ClearCurrentScrap (); + if (err == noErr) + err = GetCurrentScrap (sel); + return err; +#endif +#else /* !TARGET_API_MAC_CARBON */ + return ZeroScrap (); +#endif /* !TARGET_API_MAC_CARBON */ +} + +/* Get ownership information for SEL. Emacs can detect a change of + the ownership by comparing saved and current values of the + ownership information. */ + +Lisp_Object +mac_get_selection_ownership_info (sel) + Selection sel; +{ +#if TARGET_API_MAC_CARBON + return long_to_cons ((unsigned long) sel); +#else /* !TARGET_API_MAC_CARBON */ + ScrapStuffPtr scrap_info = InfoScrap (); + + return make_number (scrap_info->scrapCount); +#endif /* !TARGET_API_MAC_CARBON */ +} + +/* Return non-zero if VALUE is a valid selection value for TARGET. */ + +int +mac_valid_selection_value_p (value, target) + Lisp_Object value, target; +{ + return STRINGP (value); +} + +/* Put Lisp object VALUE to the selection SEL. The target type is + specified by TARGET. */ + +OSStatus +mac_put_selection_value (sel, target, value) + Selection sel; + Lisp_Object target, value; +{ + ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, 0); + + if (flavor_type == 0 || !STRINGP (value)) + return noTypeErr; + +#if TARGET_API_MAC_CARBON + return PutScrapFlavor (sel, flavor_type, kScrapFlavorMaskNone, + SBYTES (value), SDATA (value)); +#else /* !TARGET_API_MAC_CARBON */ + return PutScrap (SBYTES (value), flavor_type, SDATA (value)); +#endif /* !TARGET_API_MAC_CARBON */ +} + +/* Check if data for the target type TARGET is available in SEL. */ + +int +mac_selection_has_target_p (sel, target) + Selection sel; + Lisp_Object target; +{ + return get_flavor_type_from_symbol (target, sel) != 0; +} + +/* Get data for the target type TARGET from SEL and create a Lisp + string. Return nil if failed to get data. */ + +Lisp_Object +mac_get_selection_value (sel, target) + Selection sel; + Lisp_Object target; +{ + OSStatus err; + Lisp_Object result = Qnil; + ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, sel); +#if TARGET_API_MAC_CARBON + Size size; + + if (flavor_type) + { + err = GetScrapFlavorSize (sel, flavor_type, &size); + if (err == noErr) + { + do + { + result = make_uninit_string (size); + err = GetScrapFlavorData (sel, flavor_type, + &size, SDATA (result)); + if (err != noErr) + result = Qnil; + else if (size < SBYTES (result)) + result = make_unibyte_string (SDATA (result), size); + } + while (STRINGP (result) && size > SBYTES (result)); + } + } +#else + Handle handle; + SInt32 size, offset; + + if (flavor_type) + size = GetScrap (NULL, flavor_type, &offset); + if (size >= 0) + { + handle = NewHandle (size); + HLock (handle); + size = GetScrap (handle, flavor_type, &offset); + if (size >= 0) + result = make_unibyte_string (*handle, size); + DisposeHandle (handle); + } +#endif + + return result; +} + +/* Get the list of target types in SEL. The return value is a list of + target type symbols possibly followed by scrap flavor type + strings. */ + +Lisp_Object +mac_get_selection_target_list (sel) + Selection sel; +{ + Lisp_Object result = Qnil, rest, target; +#if TARGET_API_MAC_CARBON + OSStatus err; + UInt32 count, i, type; + ScrapFlavorInfo *flavor_info = NULL; + Lisp_Object strings = Qnil; + + err = GetScrapFlavorCount (sel, &count); + if (err == noErr) + flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count); + err = GetScrapFlavorInfoList (sel, &count, flavor_info); + if (err != noErr) + { + xfree (flavor_info); + flavor_info = NULL; + } + if (flavor_info == NULL) + count = 0; +#endif + for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest)) + { + ScrapFlavorType flavor_type = 0; + + if (CONSP (XCAR (rest)) + && (target = XCAR (XCAR (rest)), + SYMBOLP (target)) + && (flavor_type = get_flavor_type_from_symbol (target, sel))) + { + result = Fcons (target, result); +#if TARGET_API_MAC_CARBON + for (i = 0; i < count; i++) + if (flavor_info[i].flavorType == flavor_type) + { + flavor_info[i].flavorType = 0; + break; + } +#endif + } + } +#if TARGET_API_MAC_CARBON + if (flavor_info) + { + for (i = 0; i < count; i++) + if (flavor_info[i].flavorType) + { + type = EndianU32_NtoB (flavor_info[i].flavorType); + strings = Fcons (make_unibyte_string ((char *) &type, 4), strings); + } + result = nconc2 (result, strings); + xfree (flavor_info); + } +#endif + + return result; +} + + +/*********************************************************************** + Apple event support +***********************************************************************/ + +extern pascal OSErr mac_handle_apple_event P_ ((const AppleEvent *, + AppleEvent *, SInt32)); +extern void cleanup_all_suspended_apple_events P_ ((void)); + +void +init_apple_event_handler () +{ + OSErr err; + long result; + + /* Make sure we have Apple events before starting. */ + err = Gestalt (gestaltAppleEventsAttr, &result); + if (err != noErr) + abort (); + + if (!(result & (1 << gestaltAppleEventsPresent))) + abort (); + + err = AEInstallEventHandler (typeWildCard, typeWildCard, +#if TARGET_API_MAC_CARBON + NewAEEventHandlerUPP (mac_handle_apple_event), +#else + NewAEEventHandlerProc (mac_handle_apple_event), +#endif + 0L, false); + if (err != noErr) + abort (); + + atexit (cleanup_all_suspended_apple_events); +} + + +/*********************************************************************** + Drag and drop support +***********************************************************************/ + +#if TARGET_API_MAC_CARBON +extern Lisp_Object Vmac_dnd_known_types; + +static pascal OSErr mac_do_track_drag P_ ((DragTrackingMessage, WindowRef, + void *, DragRef)); +static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef)); +static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL; +static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL; + +static void +mac_store_drag_event (window, mouse_pos, modifiers, desc) + WindowRef window; + Point mouse_pos; + SInt16 modifiers; + const AEDesc *desc; +{ + struct input_event buf; + + EVENT_INIT (buf); + + buf.kind = DRAG_N_DROP_EVENT; + buf.modifiers = mac_to_emacs_modifiers (modifiers, 0); + buf.timestamp = TickCount () * (1000 / 60); + XSETINT (buf.x, mouse_pos.h); + XSETINT (buf.y, mouse_pos.v); + XSETFRAME (buf.frame_or_window, mac_window_to_frame (window)); + buf.arg = mac_aedesc_to_lisp (desc); + kbd_buffer_store_event (&buf); +} + +static pascal OSErr +mac_do_track_drag (message, window, refcon, drag) + DragTrackingMessage message; + WindowRef window; + void *refcon; + DragRef drag; +{ + OSErr err = noErr; + static int can_accept; + UInt16 num_items, index; + + if (GetFrontWindowOfClass (kMovableModalWindowClass, false)) + return dragNotAcceptedErr; + + switch (message) + { + case kDragTrackingEnterHandler: + err = CountDragItems (drag, &num_items); + if (err != noErr) + break; + can_accept = 0; + for (index = 1; index <= num_items; index++) + { + ItemReference item; + FlavorFlags flags; + Lisp_Object rest; + + err = GetDragItemReferenceNumber (drag, index, &item); + if (err != noErr) + continue; + for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest)) + { + Lisp_Object str; + FlavorType type; + + str = XCAR (rest); + if (!(STRINGP (str) && SBYTES (str) == 4)) + continue; + type = EndianU32_BtoN (*((UInt32 *) SDATA (str))); + + err = GetFlavorFlags (drag, item, type, &flags); + if (err == noErr) + { + can_accept = 1; + break; + } + } + } + break; + + case kDragTrackingEnterWindow: + if (can_accept) + { + RgnHandle hilite_rgn = NewRgn (); + + if (hilite_rgn) + { + Rect r; + + GetWindowPortBounds (window, &r); + OffsetRect (&r, -r.left, -r.top); + RectRgn (hilite_rgn, &r); + ShowDragHilite (drag, hilite_rgn, true); + DisposeRgn (hilite_rgn); + } + SetThemeCursor (kThemeCopyArrowCursor); + } + break; + + case kDragTrackingInWindow: + break; + + case kDragTrackingLeaveWindow: + if (can_accept) + { + HideDragHilite (drag); + SetThemeCursor (kThemeArrowCursor); + } + break; + + case kDragTrackingLeaveHandler: + break; + } + + if (err != noErr) + return dragNotAcceptedErr; + return noErr; +} + +static pascal OSErr +mac_do_receive_drag (window, refcon, drag) + WindowRef window; + void *refcon; + DragRef drag; +{ + OSErr err; + int num_types, i; + Lisp_Object rest, str; + FlavorType *types; + AppleEvent apple_event; + Point mouse_pos; + SInt16 modifiers; + + if (GetFrontWindowOfClass (kMovableModalWindowClass, false)) + return dragNotAcceptedErr; + + num_types = 0; + for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest)) + { + str = XCAR (rest); + if (STRINGP (str) && SBYTES (str) == 4) + num_types++; + } + + types = xmalloc (sizeof (FlavorType) * num_types); + i = 0; + for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest)) + { + str = XCAR (rest); + if (STRINGP (str) && SBYTES (str) == 4) + types[i++] = EndianU32_BtoN (*((UInt32 *) SDATA (str))); + } + + err = create_apple_event_from_drag_ref (drag, num_types, types, + &apple_event); + xfree (types); + + if (err == noErr) + err = GetDragMouse (drag, &mouse_pos, NULL); + if (err == noErr) + { + GlobalToLocal (&mouse_pos); + err = GetDragModifiers (drag, NULL, NULL, &modifiers); + } + if (err == noErr) + { + UInt32 key_modifiers = modifiers; + + err = AEPutParamPtr (&apple_event, kEventParamKeyModifiers, + typeUInt32, &key_modifiers, sizeof (UInt32)); + } + + if (err == noErr) + { + mac_store_drag_event (window, mouse_pos, 0, &apple_event); + AEDisposeDesc (&apple_event); + mac_wakeup_from_rne (); + return noErr; + } + else + return dragNotAcceptedErr; +} +#endif /* TARGET_API_MAC_CARBON */ + +static OSErr +install_drag_handler (window) + WindowRef window; +{ + OSErr err = noErr; + +#if TARGET_API_MAC_CARBON + if (mac_do_track_dragUPP == NULL) + mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag); + if (mac_do_receive_dragUPP == NULL) + mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag); + + err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL); + if (err == noErr) + err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL); +#endif + + return err; +} + +static void +remove_drag_handler (window) + WindowRef window; +{ +#if TARGET_API_MAC_CARBON + if (mac_do_track_dragUPP) + RemoveTrackingHandler (mac_do_track_dragUPP, window); + if (mac_do_receive_dragUPP) + RemoveReceiveHandler (mac_do_receive_dragUPP, window); +#endif +} + +#if TARGET_API_MAC_CARBON +/* Return default value for mac-dnd-known-types. */ + +Lisp_Object +mac_dnd_default_known_types () +{ + Lisp_Object result = list4 (build_string ("hfs "), build_string ("utxt"), + build_string ("TEXT"), build_string ("TIFF")); + +#ifdef MAC_OSX + result = Fcons (build_string ("furl"), result); +#endif + + return result; +} +#endif + + +/*********************************************************************** + Services menu support +***********************************************************************/ + +#ifdef MAC_OSX +extern Lisp_Object Qservice, Qpaste, Qperform; +extern Lisp_Object Vmac_service_selection; + +static OSStatus +mac_store_service_event (event) + EventRef event; +{ + OSStatus err; + Lisp_Object id_key; + int num_params; + const EventParamName *names; + const EventParamType *types; + static const EventParamName names_pfm[] = + {kEventParamServiceMessageName, kEventParamServiceUserData}; + static const EventParamType types_pfm[] = + {typeCFStringRef, typeCFStringRef}; + + switch (GetEventKind (event)) + { + case kEventServicePaste: + id_key = Qpaste; + num_params = 0; + names = NULL; + types = NULL; + break; + + case kEventServicePerform: + id_key = Qperform; + num_params = sizeof (names_pfm) / sizeof (names_pfm[0]); + names = names_pfm; + types = types_pfm; + break; + + default: + abort (); + } + + err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key, + event, num_params, + names, types); + + return err; +} + +static OSStatus +copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type) + ScrapRef from_scrap, to_scrap; + ScrapFlavorType flavor_type; +{ + OSStatus err; + Size size, size_allocated; + char *buf = NULL; + + err = GetScrapFlavorSize (from_scrap, flavor_type, &size); + if (err == noErr) + buf = xmalloc (size); + while (buf) + { + size_allocated = size; + err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf); + if (err != noErr) + { + xfree (buf); + buf = NULL; + } + else if (size_allocated < size) + buf = xrealloc (buf, size); + else + break; + } + if (err == noErr) + { + if (buf == NULL) + err = memFullErr; + else + { + err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone, + size, buf); + xfree (buf); + } + } + + return err; +} + +static OSStatus +mac_handle_service_event (call_ref, event, data) + EventHandlerCallRef call_ref; + EventRef event; + void *data; +{ + OSStatus err = noErr; + ScrapRef cur_scrap, specific_scrap; + UInt32 event_kind = GetEventKind (event); + CFMutableArrayRef copy_types, paste_types; + CFStringRef type; + Lisp_Object rest; + ScrapFlavorType flavor_type; + + /* Check if Vmac_service_selection is a valid selection that has a + corresponding scrap. */ + if (!SYMBOLP (Vmac_service_selection)) + err = eventNotHandledErr; + else + err = mac_get_selection_from_symbol (Vmac_service_selection, 0, &cur_scrap); + if (!(err == noErr && cur_scrap)) + return eventNotHandledErr; + + switch (event_kind) + { + case kEventServiceGetTypes: + /* Set paste types. */ + err = GetEventParameter (event, kEventParamServicePasteTypes, + typeCFMutableArrayRef, NULL, + sizeof (CFMutableArrayRef), NULL, + &paste_types); + if (err != noErr) + break; + + for (rest = Vselection_converter_alist; CONSP (rest); + rest = XCDR (rest)) + if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest))) + && (flavor_type = + get_flavor_type_from_symbol (XCAR (XCAR (rest)), 0))) + { + type = CreateTypeStringWithOSType (flavor_type); + if (type) + { + CFArrayAppendValue (paste_types, type); + CFRelease (type); + } + } + + /* Set copy types. */ + err = GetEventParameter (event, kEventParamServiceCopyTypes, + typeCFMutableArrayRef, NULL, + sizeof (CFMutableArrayRef), NULL, + ©_types); + if (err != noErr) + break; + + if (NILP (Fx_selection_owner_p (Vmac_service_selection))) + break; + else + goto copy_all_flavors; + + case kEventServiceCopy: + err = GetEventParameter (event, kEventParamScrapRef, + typeScrapRef, NULL, + sizeof (ScrapRef), NULL, &specific_scrap); + if (err != noErr + || NILP (Fx_selection_owner_p (Vmac_service_selection))) + { + err = eventNotHandledErr; + break; + } + + copy_all_flavors: + { + UInt32 count, i; + ScrapFlavorInfo *flavor_info = NULL; + ScrapFlavorFlags flags; + + err = GetScrapFlavorCount (cur_scrap, &count); + if (err == noErr) + flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count); + err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info); + if (err != noErr) + { + xfree (flavor_info); + flavor_info = NULL; + } + if (flavor_info == NULL) + break; + + for (i = 0; i < count; i++) + { + flavor_type = flavor_info[i].flavorType; + err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags); + if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly)) + { + if (event_kind == kEventServiceCopy) + err = copy_scrap_flavor_data (cur_scrap, specific_scrap, + flavor_type); + else /* event_kind == kEventServiceGetTypes */ + { + type = CreateTypeStringWithOSType (flavor_type); + if (type) + { + CFArrayAppendValue (copy_types, type); + CFRelease (type); + } + } + } + } + xfree (flavor_info); + } + break; + + case kEventServicePaste: + case kEventServicePerform: + { + int data_exists_p = 0; + + err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef, + NULL, sizeof (ScrapRef), NULL, + &specific_scrap); + if (err == noErr) + err = mac_clear_selection (&cur_scrap); + if (err == noErr) + for (rest = Vselection_converter_alist; CONSP (rest); + rest = XCDR (rest)) + { + if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest))))) + continue; + flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)), + specific_scrap); + if (flavor_type == 0) + continue; + err = copy_scrap_flavor_data (specific_scrap, cur_scrap, + flavor_type); + if (err == noErr) + data_exists_p = 1; + } + if (!data_exists_p) + err = eventNotHandledErr; + else + err = mac_store_service_event (event); + } + break; + } + + if (err != noErr) + err = eventNotHandledErr; + return err; +} + +static OSStatus +install_service_handler () +{ + static const EventTypeSpec specs[] = + {{kEventClassService, kEventServiceGetTypes}, + {kEventClassService, kEventServiceCopy}, + {kEventClassService, kEventServicePaste}, + {kEventClassService, kEventServicePerform}}; + + return InstallApplicationEventHandler (NewEventHandlerUPP + (mac_handle_service_event), + GetEventTypeCount (specs), + specs, NULL, NULL); +} +#endif /* MAC_OSX */ + + +/*********************************************************************** + Initialization + ***********************************************************************/ + +void +mac_toolbox_initialize () +{ + any_help_event_p = 0; + + init_menu_bar (); + +#ifdef MAC_OSX + init_apple_event_handler (); +#endif +#if USE_MAC_TSM + init_tsm (); +#endif +} From f1a374593b45eb236a8dd5c3b8a12416ce39cb2e Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:56:59 +0000 Subject: [PATCH 04/56] (MacObjects): Add mactoolbox.c.x. (mactoolbox.c.x): New target. --- mac/ChangeLog | 5 +++++ mac/makefile.MPW | 20 +++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mac/ChangeLog b/mac/ChangeLog index 94f2afe3ae5..e9f832f1fd3 100644 --- a/mac/ChangeLog +++ b/mac/ChangeLog @@ -1,3 +1,8 @@ +2008-04-06 YAMAMOTO Mitsuharu + + * makefile.MPW (MacObjects): Add mactoolbox.c.x. + (mactoolbox.c.x): New target. + 2008-03-26 Chong Yidong * Version 22.2 released. diff --git a/mac/makefile.MPW b/mac/makefile.MPW index 923dedb3f52..a95a16ed40f 100644 --- a/mac/makefile.MPW +++ b/mac/makefile.MPW @@ -133,7 +133,8 @@ MacObjects = "{Src}macfns.c.x" ¶ "{Src}macmenu.c.x" ¶ "{Src}macselect.c.x" ¶ - "{Src}macterm.c.x" + "{Src}macterm.c.x" ¶ + "{Src}mactoolbox.c.x" StdLibraries = ¶ "{SharedLibraries}CarbonLib" ¶ @@ -981,6 +982,23 @@ buildobj.lst "{Src}coding.h" ¶ "{Src}ccl.h" +{Src}mactoolbox.c.x Ä ¶ + {CONFIG_H_GROUP} ¶ + "{Src}lisp.h" ¶ + "{Src}macterm.h" ¶ + "{Src}macgui.h" ¶ + "{Src}frame.h" ¶ + "{Src}charset.h" ¶ + "{Src}coding.h" ¶ + "{Src}ccl.h" ¶ + {DISPEXTERN_H_GROUP} ¶ + "{Src}fontset.h" ¶ + "{Src}termhooks.h" ¶ + "{Src}buffer.h" ¶ + "{Src}window.h" ¶ + "{Src}keyboard.h" ¶ + {BLOCKINPUT_H_GROUP} + #----------------------------------------# # Variables and rules for target "Clean" # From f4f1eb1002f4d49d64cf2452d55b120a71526dc7 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:57:25 +0000 Subject: [PATCH 05/56] (MAC_OBJ): Add mactoolbox.o. (mactoolbox.o): New target. --- src/Makefile.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Makefile.in b/src/Makefile.in index 74ab05bec9c..97c630e24c0 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -575,7 +575,7 @@ CYGWIN_OBJ = sheap.o #ifdef HAVE_CARBON mac = $(dot)$(dot)/mac/ -MAC_OBJ = mac.o macterm.o macfns.o macmenu.o macselect.o fontset.o fringe.o image.o +MAC_OBJ = mac.o macterm.o macfns.o macmenu.o macselect.o fontset.o fringe.o image.o mactoolbox.o emacsapp = $(PWD)/$(mac)Emacs.app/ emacsappsrc = ${srcdir}/../mac/Emacs.app/ #endif @@ -1287,6 +1287,9 @@ macterm.o: blockinput.h atimer.h systime.h syssignal.h macterm.h macgui.h \ process.h coding.h $(config_h) macselect.o: blockinput.h atimer.h systime.h macterm.h macgui.h frame.h \ keymap.h $(config_h) +mactoolbox.o: blockinput.h atimer.h systime.h macterm.h macgui.h frame.h \ + charset.h coding.h ccl.h dispextern.h fontset.h termhooks.h buffer.h \ + window.h keyboard.h $(config_h) ${emacsapp}Contents/Resources/English.lproj: mkdir -p $@ From cc69f23aedadf9cc6463cc47b431910694467a99 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:57:37 +0000 Subject: [PATCH 06/56] [MAC_OSX] (select_and_poll_event, sys_select): Use mac_run_loop_run_once instead of CFRunLoopRunInMode. --- src/mac.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/src/mac.c b/src/mac.c index 74cfeb24865..0ae233f048e 100644 --- a/src/mac.c +++ b/src/mac.c @@ -4989,8 +4989,8 @@ extern int noninteractive; SELECT_TIMEOUT_THRESHOLD_RUNLOOP seconds). -> Create CFSocket for each socket and add it into the current event RunLoop so that the current event loop gets quit when - the socket becomes ready. Then CFRunLoopRunInMode can wait - for both kinds of inputs. + the socket becomes ready. Then mac_run_loop_run_once can + wait for both kinds of inputs. 4. Otherwise. -> Periodically poll the window input channel while repeatedly executing `select' with a short timeout @@ -5045,7 +5045,7 @@ select_and_poll_event (nfds, rfds, wfds, efds, timeout) if (efds) oefds = *efds; } - /* Try detect_input_pending before CFRunLoopRunInMode in the same + /* Try detect_input_pending before mac_run_loop_run_once in the same BLOCK_INPUT block, in case that some input has already been read asynchronously. */ BLOCK_INPUT; @@ -5062,15 +5062,7 @@ select_and_poll_event (nfds, rfds, wfds, efds, timeout) if (timeoutval == 0.0) timedout_p = 1; else - { -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (NULL); -#endif - if (CFRunLoopRunInMode (kCFRunLoopDefaultMode, - timeoutval >= 0 ? timeoutval : 100000, true) - == kCFRunLoopRunTimedOut) - timedout_p = 1; - } + timedout_p = mac_run_loop_run_once (timeoutval); if (timeout == NULL && timedout_p) { @@ -5193,7 +5185,7 @@ sys_select (nfds, rfds, wfds, efds, timeout) if (timeoutval > 0 && timeoutval <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP) goto poll_periodically; - /* Try detect_input_pending before CFRunLoopRunInMode in the + /* Try detect_input_pending before mac_run_loop_run_once in the same BLOCK_INPUT block, in case that some input has already been read asynchronously. */ BLOCK_INPUT; @@ -5246,13 +5238,7 @@ sys_select (nfds, rfds, wfds, efds, timeout) CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode); } -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (NULL); -#endif - if (CFRunLoopRunInMode (kCFRunLoopDefaultMode, - timeoutval >= 0 ? timeoutval : 100000, true) - == kCFRunLoopRunTimedOut) - timedout_p = 1; + timedout_p = mac_run_loop_run_once (timeoutval); for (fd = minfd; fd < nfds; fd++) if (FD_ISSET (fd, rfds) || (wfds && FD_ISSET (fd, wfds))) From 9ef833acf43ab762ead83ec8dc5fe162d4db40c0 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:57:47 +0000 Subject: [PATCH 07/56] (x_set_background_color, mac_window, x_create_tip_frame): Use mac_set_frame_window_background instead of XSetWindowBackground. (x_set_tool_bar_lines) [USE_MAC_TOOLBAR]: Use mac_is_window_toolbar_visible instead of IsWindowToolbarVisible. (x_set_name_internal) [TARGET_API_MAC_CARBON]: Use mac_set_window_title instead of SetWindowTitleWithCFString. (mac_update_proxy_icon) [TARGET_API_MAC_CARBON]: Remove BLOCK_INPUT. Move function to mactoolbox.c. (mac_update_title_bar) [TARGET_API_MAC_CARBON]: Use mac_set_window_modified instead of SetWindowModified. Add BLOCK_INPUT around mac_set_window_modified/mac_update_proxy_icon. (mac_window, x_create_tip_frame): Use mac_create_frame_window. (Fx_focus_frame): Use mac_front_non_floating_window instead of FrontNonFloatingWindow. Use mac_activate_window instead of ActivateWindow. Use mac_active_non_floating_window instead of ActiveNonFloatingWindow. (show_hourglass, hide_hourglass) [TARGET_API_MAC_CARBON]: Use mac_show_hourglass and mac_hide_hourglass. (compute_tip_xy) [TARGET_API_MAC_CARBON]: Use mac_get_global_mouse instead of GetGlobalMouse. (Fx_show_tip): Use mac_move_window/mac_size_window/mac_show_window instead of MoveWindow/SizeWindow/ShowWindow, respectively. Use mac_bring_window_to_front instead of BringToFront. (Qfile_name_history) [TARGET_API_MAC_CARBON]: Move extern to mactoolbox.c. (Fx_file_dialog) [TARGET_API_MAC_CARBON]: Move function body to mac_file_dialog in mactoolbox.c. Use mac_file_dialog. (mac_nav_event_callback) [TARGET_API_MAC_CARBON]: Move function to mactoolbox.c. --- src/macfns.c | 427 +++++---------------------------------------------- 1 file changed, 35 insertions(+), 392 deletions(-) diff --git a/src/macfns.c b/src/macfns.c index 23c2fca7cb0..d66c56e6d84 100644 --- a/src/macfns.c +++ b/src/macfns.c @@ -1347,7 +1347,7 @@ x_set_background_color (f, arg, oldval) BLOCK_INPUT; XSetBackground (dpy, mac->normal_gc, bg); XSetForeground (dpy, mac->reverse_gc, bg); - XSetWindowBackground (dpy, FRAME_MAC_WINDOW (f), bg); + mac_set_frame_window_background (f, bg); XSetForeground (dpy, mac->cursor_gc, bg); UNBLOCK_INPUT; @@ -1687,7 +1687,8 @@ x_set_tool_bar_lines (f, value, oldval) if (nlines) { FRAME_EXTERNAL_TOOL_BAR (f) = 1; - if (FRAME_MAC_P (f) && !IsWindowToolbarVisible (FRAME_MAC_WINDOW (f))) + if (FRAME_MAC_P (f) + && !mac_is_window_toolbar_visible (FRAME_MAC_WINDOW (f))) /* Make sure next redisplay shows the tool bar. */ XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = Qt; } @@ -1773,7 +1774,7 @@ x_set_name_internal (f, name) CFStringRef windowTitle = cfstring_create_with_utf8_cstring (SDATA (name)); - SetWindowTitleWithCFString (FRAME_MAC_WINDOW (f), windowTitle); + mac_set_window_title (FRAME_MAC_WINDOW (f), windowTitle); CFRelease (windowTitle); #else Str255 windowTitle; @@ -1938,98 +1939,6 @@ mac_set_font (f, arg, oldval) #endif } -#if TARGET_API_MAC_CARBON -static void -mac_update_proxy_icon (f) - struct frame *f; -{ - OSStatus err; - Lisp_Object file_name = - XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer)->filename; - Window w = FRAME_MAC_WINDOW (f); - AliasHandle alias = NULL; - - BLOCK_INPUT; - - err = GetWindowProxyAlias (w, &alias); - if (err == errWindowDoesNotHaveProxy && !STRINGP (file_name)) - goto out; - - if (STRINGP (file_name)) - { - AEDesc desc; -#ifdef MAC_OSX - FSRef fref, fref_proxy; -#else - FSSpec fss, fss_proxy; -#endif - Boolean changed; - Lisp_Object encoded_file_name = ENCODE_FILE (file_name); - -#ifdef MAC_OSX - err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name), - SBYTES (encoded_file_name), typeFSRef, &desc); -#else - SetPortWindowPort (w); - err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name), - SBYTES (encoded_file_name), typeFSS, &desc); -#endif - if (err == noErr) - { -#ifdef MAC_OSX - err = AEGetDescData (&desc, &fref, sizeof (FSRef)); -#else - err = AEGetDescData (&desc, &fss, sizeof (FSSpec)); -#endif - AEDisposeDesc (&desc); - } - if (err == noErr) - { - if (alias) - { - /* (FS)ResolveAlias never sets `changed' to true if - `alias' is minimal. */ -#ifdef MAC_OSX - err = FSResolveAlias (NULL, alias, &fref_proxy, &changed); - if (err == noErr) - err = FSCompareFSRefs (&fref, &fref_proxy); -#else - err = ResolveAlias (NULL, alias, &fss_proxy, &changed); - if (err == noErr) - err = !(fss.vRefNum == fss_proxy.vRefNum - && fss.parID == fss_proxy.parID - && EqualString (fss.name, fss_proxy.name, - false, true)); -#endif - } - if (err != noErr || alias == NULL) - { - if (alias) - DisposeHandle ((Handle) alias); -#ifdef MAC_OSX - err = FSNewAliasMinimal (&fref, &alias); -#else - err = NewAliasMinimal (&fss, &alias); -#endif - changed = true; - } - } - if (err == noErr) - if (changed) - err = SetWindowProxyAlias (w, alias); - } - - if (alias) - DisposeHandle ((Handle) alias); - - if (err != noErr || !STRINGP (file_name)) - RemoveWindowProxy (w); - - out: - UNBLOCK_INPUT; -} -#endif - void mac_update_title_bar (f, save_match_data) struct frame *f; @@ -2051,9 +1960,11 @@ mac_update_title_bar (f, save_match_data) || (!MINI_WINDOW_P (w) && (modified_p != !NILP (w->last_had_star)))) { - SetWindowModified (FRAME_MAC_WINDOW (f), - !MINI_WINDOW_P (w) && modified_p); + BLOCK_INPUT; + mac_set_window_modified (FRAME_MAC_WINDOW (f), + !MINI_WINDOW_P (w) && modified_p); mac_update_proxy_icon (f); + UNBLOCK_INPUT; } #endif } @@ -2248,52 +2159,12 @@ static void mac_window (f) struct frame *f; { - Rect r; - BLOCK_INPUT; - SetRect (&r, f->left_pos, f->top_pos, - f->left_pos + FRAME_PIXEL_WIDTH (f), - f->top_pos + FRAME_PIXEL_HEIGHT (f)); -#if TARGET_API_MAC_CARBON - CreateNewWindow (kDocumentWindowClass, - kWindowStandardDocumentAttributes -#ifdef MAC_OSX - | kWindowToolbarButtonAttribute -#endif - , &r, &FRAME_MAC_WINDOW (f)); - if (FRAME_MAC_WINDOW (f)) - { - SetWRefCon (FRAME_MAC_WINDOW (f), (long) f->output_data.mac); - if (install_window_handler (FRAME_MAC_WINDOW (f)) != noErr) - { - DisposeWindow (FRAME_MAC_WINDOW (f)); - FRAME_MAC_WINDOW (f) = NULL; - } - } -#else /* !TARGET_API_MAC_CARBON */ - FRAME_MAC_WINDOW (f) - = NewCWindow (NULL, &r, "\p", false, zoomDocProc, - (WindowRef) -1, 1, (long) f->output_data.mac); -#endif /* !TARGET_API_MAC_CARBON */ - /* so that update events can find this mac_output struct */ - f->output_data.mac->mFP = f; /* point back to emacs frame */ + mac_create_frame_window (f, 0); -#ifndef MAC_OSX if (FRAME_MAC_WINDOW (f)) - { - ControlRef root_control; - - if (CreateRootControl (FRAME_MAC_WINDOW (f), &root_control) != noErr) - { - DisposeWindow (FRAME_MAC_WINDOW (f)); - FRAME_MAC_WINDOW (f) = NULL; - } - } -#endif - if (FRAME_MAC_WINDOW (f)) - XSetWindowBackground (FRAME_MAC_DISPLAY(f), FRAME_MAC_WINDOW (f), - FRAME_BACKGROUND_PIXEL (f)); + mac_set_frame_window_background (f, FRAME_BACKGROUND_PIXEL (f)); #if USE_MAC_TOOLBAR /* At the moment, the size of the tool bar is not yet known. We @@ -2880,7 +2751,7 @@ FRAME nil means use the selected frame. */) if (!front_p) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 - if (FrontNonFloatingWindow () == FRAME_MAC_WINDOW (f)) + if (mac_front_non_floating_window () == FRAME_MAC_WINDOW (f)) SetFrontProcessWithOptions (¤t_psn, kSetFrontProcessFrontWindowOnly); else @@ -2889,8 +2760,8 @@ FRAME nil means use the selected frame. */) } #ifdef MAC_OSX - ActivateWindow (ActiveNonFloatingWindow (), false); - ActivateWindow (FRAME_MAC_WINDOW (f), true); + mac_activate_window (mac_active_non_floating_window (), false); + mac_activate_window (FRAME_MAC_WINDOW (f), true); #else #if !TARGET_API_MAC_CARBON /* SelectWindow (Non-Carbon) does not issue deactivate events if the @@ -3678,26 +3549,7 @@ show_hourglass (timer) if (FRAME_LIVE_P (f) && FRAME_MAC_P (f) && FRAME_MAC_WINDOW (f) != tip_window) - { -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - if (!f->output_data.mac->hourglass_control) - { - Window w = FRAME_MAC_WINDOW (f); - Rect r; - ControlRef c; - - GetWindowPortBounds (w, &r); - r.left = r.right - HOURGLASS_WIDTH; - r.bottom = r.top + HOURGLASS_HEIGHT; - if (CreateChasingArrowsControl (w, &r, &c) == noErr) - f->output_data.mac->hourglass_control = c; - } - - if (f->output_data.mac->hourglass_control) - ShowControl (f->output_data.mac->hourglass_control); - } + mac_show_hourglass (f); } hourglass_shown_p = 1; @@ -3723,15 +3575,8 @@ hide_hourglass () { struct frame *f = XFRAME (frame); - if (FRAME_MAC_P (f) - /* Watch out for newly created frames. */ - && f->output_data.mac->hourglass_control) - { -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - HideControl (f->output_data.mac->hourglass_control); - } + if (FRAME_MAC_P (f)) + mac_hide_hourglass (f); } hourglass_shown_p = 0; @@ -3972,33 +3817,17 @@ x_create_tip_frame (dpyinfo, parms, text) window_prompting = x_figure_window_size (f, parms, 0); - { - Rect r; + BLOCK_INPUT; - BLOCK_INPUT; - SetRect (&r, 0, 0, 1, 1); -#if TARGET_API_MAC_CARBON - if (CreateNewWindow (kHelpWindowClass, -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 - kWindowIgnoreClicksAttribute | -#endif - kWindowNoUpdatesAttribute | - kWindowNoActivatesAttribute, - &r, &tip_window) == noErr) -#else - if (tip_window = NewCWindow (NULL, &r, "\p", false, plainDBox, - NULL, false, 0L)) -#endif - { - FRAME_MAC_WINDOW (f) = tip_window; - XSetWindowBackground (FRAME_MAC_DISPLAY(f), tip_window, - FRAME_BACKGROUND_PIXEL (f)); - SetWRefCon (tip_window, (long) f->output_data.mac); - /* so that update events can find this mac_output struct */ - f->output_data.mac->mFP = f; - } - UNBLOCK_INPUT; - } + mac_create_frame_window (f, 1); + + if (FRAME_MAC_WINDOW (f)) + { + mac_set_frame_window_background (f, FRAME_BACKGROUND_PIXEL (f)); + tip_window = FRAME_MAC_WINDOW (f); + } + + UNBLOCK_INPUT; x_make_gc (f); @@ -4095,7 +3924,7 @@ compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y) BLOCK_INPUT; #if TARGET_API_MAC_CARBON - GetGlobalMouse (&mouse_pos); + mac_get_global_mouse (&mouse_pos); #else GetMouse (&mouse_pos); LocalToGlobal (&mouse_pos); @@ -4219,7 +4048,7 @@ Text larger than the specified size is clipped. */) BLOCK_INPUT; compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f), &root_x, &root_y); - MoveWindow (FRAME_MAC_WINDOW (f), root_x, root_y, false); + mac_move_window (FRAME_MAC_WINDOW (f), root_x, root_y, false); UNBLOCK_INPUT; goto start_timer; } @@ -4321,10 +4150,10 @@ Text larger than the specified size is clipped. */) compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y); BLOCK_INPUT; - MoveWindow (FRAME_MAC_WINDOW (f), root_x, root_y, false); - SizeWindow (FRAME_MAC_WINDOW (f), width, height, true); - ShowWindow (FRAME_MAC_WINDOW (f)); - BringToFront (FRAME_MAC_WINDOW (f)); + mac_move_window (FRAME_MAC_WINDOW (f), root_x, root_y, false); + mac_size_window (FRAME_MAC_WINDOW (f), width, height, true); + mac_show_window (FRAME_MAC_WINDOW (f)); + mac_bring_window_to_front (FRAME_MAC_WINDOW (f)); UNBLOCK_INPUT; FRAME_PIXEL_WIDTH (f) = width; @@ -4385,25 +4214,11 @@ Value is t if tooltip was open, nil otherwise. */) -#if TARGET_API_MAC_CARBON /*********************************************************************** File selection dialog ***********************************************************************/ -static pascal void mac_nav_event_callback P_ ((NavEventCallbackMessage, - NavCBRecPtr, void *)); - -/** - There is a relatively standard way to do this using applescript to run - a (choose file) method. However, this doesn't do "the right thing" - by working only if the find-file occurred during a menu or toolbar - click. So we must do the file dialog by hand, using the navigation - manager. This also has more flexibility in determining the default - directory and whether or not we are going to choose a file. - **/ - -extern Lisp_Object Qfile_name_history; - +#if TARGET_API_MAC_CARBON DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, doc: /* Read file name, prompting with PROMPT in directory DIR. Use a file selection dialog. @@ -4413,182 +4228,10 @@ If ONLY-DIR-P is non-nil, the user can only select directories. */) (prompt, dir, default_filename, mustmatch, only_dir_p) Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p; { - Lisp_Object file = Qnil; - int count = SPECPDL_INDEX (); - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; - char filename[MAXPATHLEN]; - static NavEventUPP mac_nav_event_callbackUPP = NULL; - - check_mac (); - - GCPRO6 (prompt, dir, default_filename, mustmatch, file, only_dir_p); - CHECK_STRING (prompt); - CHECK_STRING (dir); - - /* Create the dialog with PROMPT as title, using DIR as initial - directory and using "*" as pattern. */ - dir = Fexpand_file_name (dir, Qnil); - - { - OSStatus status; - NavDialogCreationOptions options; - NavDialogRef dialogRef; - NavTypeListHandle fileTypes = NULL; - NavUserAction userAction; - CFStringRef message=NULL, saveName = NULL; - - BLOCK_INPUT; - /* No need for a callback function because we are modal */ - NavGetDefaultDialogCreationOptions(&options); - options.modality = kWindowModalityAppModal; - options.location.h = options.location.v = -1; - options.optionFlags = kNavDefaultNavDlogOptions; - options.optionFlags |= kNavAllFilesInPopup; /* All files allowed */ - options.optionFlags |= kNavSelectAllReadableItem; - options.optionFlags &= ~kNavAllowMultipleFiles; - if (!NILP(prompt)) - { - message = cfstring_create_with_string (prompt); - options.message = message; - } - /* Don't set the application, let it use default. - options.clientName = CFSTR ("Emacs"); - */ - - if (mac_nav_event_callbackUPP == NULL) - mac_nav_event_callbackUPP = NewNavEventUPP (mac_nav_event_callback); - - if (!NILP (only_dir_p)) - status = NavCreateChooseFolderDialog(&options, mac_nav_event_callbackUPP, - NULL, NULL, &dialogRef); - else if (NILP (mustmatch)) - { - /* This is a save dialog */ - options.optionFlags |= kNavDontConfirmReplacement; - options.actionButtonLabel = CFSTR ("Ok"); - options.windowTitle = CFSTR ("Enter name"); - - if (STRINGP (default_filename)) - { - Lisp_Object utf8 = ENCODE_UTF_8 (default_filename); - char *begPtr = SDATA(utf8); - char *filePtr = begPtr + SBYTES(utf8); - while (filePtr != begPtr && !IS_DIRECTORY_SEP(filePtr[-1])) - filePtr--; - saveName = cfstring_create_with_utf8_cstring (filePtr); - options.saveFileName = saveName; - options.optionFlags |= kNavSelectDefaultLocation; - } - status = NavCreatePutFileDialog(&options, - 'TEXT', kNavGenericSignature, - mac_nav_event_callbackUPP, NULL, - &dialogRef); - } - else - { - /* This is an open dialog*/ - status = NavCreateChooseFileDialog(&options, fileTypes, - mac_nav_event_callbackUPP, NULL, - NULL, NULL, &dialogRef); - } - - /* Set the default location and continue*/ - if (status == noErr) - { - Lisp_Object encoded_dir = ENCODE_FILE (dir); - AEDesc defLocAed; - - status = AECreateDesc (TYPE_FILE_NAME, SDATA (encoded_dir), - SBYTES (encoded_dir), &defLocAed); - if (status == noErr) - { - NavCustomControl(dialogRef, kNavCtlSetLocation, (void*) &defLocAed); - AEDisposeDesc(&defLocAed); - } - status = NavDialogRun(dialogRef); - } - - if (saveName) CFRelease(saveName); - if (message) CFRelease(message); - - if (status == noErr) { - userAction = NavDialogGetUserAction(dialogRef); - switch (userAction) - { - case kNavUserActionNone: - case kNavUserActionCancel: - break; /* Treat cancel like C-g */ - case kNavUserActionOpen: - case kNavUserActionChoose: - case kNavUserActionSaveAs: - { - NavReplyRecord reply; - Size len; - - status = NavDialogGetReply(dialogRef, &reply); - if (status != noErr) - break; - status = AEGetNthPtr (&reply.selection, 1, TYPE_FILE_NAME, - NULL, NULL, filename, - sizeof (filename) - 1, &len); - if (status == noErr) - { - len = min (len, sizeof (filename) - 1); - filename[len] = '\0'; - if (reply.saveFileName) - { - /* If it was a saved file, we need to add the file name */ - if (len && len < sizeof (filename) - 1 - && filename[len-1] != '/') - filename[len++] = '/'; - CFStringGetCString(reply.saveFileName, filename+len, - sizeof (filename) - len, -#ifdef MAC_OSX - kCFStringEncodingUTF8 -#else - CFStringGetSystemEncoding () -#endif - ); - } - file = DECODE_FILE (make_unibyte_string (filename, - strlen (filename))); - } - NavDisposeReply(&reply); - } - break; - } - NavDialogDispose(dialogRef); - UNBLOCK_INPUT; - } - else { - UNBLOCK_INPUT; - /* Fall back on minibuffer if there was a problem */ - file = Fcompleting_read (prompt, intern ("read-file-name-internal"), - dir, mustmatch, dir, Qfile_name_history, - default_filename, Qnil); - } - } - - UNGCPRO; - - /* Make "Cancel" equivalent to C-g. */ - if (NILP (file)) - Fsignal (Qquit, Qnil); - - return unbind_to (count, file); -} - - -/* Need to register some event callback function for enabling drag and - drop in Navigation Service dialogs. */ -static pascal void -mac_nav_event_callback (selector, parms, data) - NavEventCallbackMessage selector; - NavCBRecPtr parms; - void *data ; -{ + return mac_file_dialog (prompt, dir, default_filename, mustmatch, only_dir_p); } #endif + /*********************************************************************** Fonts From f3821d294580e2e7285d8cbd28b2a2dc773e31f5 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:58:05 +0000 Subject: [PATCH 08/56] [!HAVE_CARBON]: Include Quickdraw.h instead of QuickDraw.h. (XtPointer): Move typedef from macmenu.c. (enum button_type): Move enum from macmenu.c. (widget_value): Move typedef from macmenu.c. (M_APPLE, I_ABOUT, EXTRA_STACK_ALLOC, ARGV_STRING_LIST_ID) (DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN, DIALOG_RIGHT_MARGIN) (DIALOG_BOTTOM_MARGIN, DIALOG_MIN_INNER_WIDTH, DIALOG_MAX_INNER_WIDTH) (DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE) (DIALOG_BUTTON_BUTTON_VERTICAL_SPACE, DIALOG_BUTTON_MIN_WIDTH) (DIALOG_TEXT_MIN_HEIGHT, DIALOG_TEXT_BUTTONS_VERTICAL_SPACE) (DIALOG_ICON_WIDTH, DIALOG_ICON_HEIGHT, DIALOG_ICON_LEFT_MARGIN) (DIALOG_ICON_TOP_MARGIN): Move defines from macmenu.c. (Selection): Move typedef from macselect.c. (RAM_TOO_LARGE_ALERT_ID, ABOUT_ALERT_ID) [MAC_OS8]: Move defines from macterm.c. (mac_set_window_title, mac_set_window_modified, mac_is_window_visible) (mac_is_window_collapsed, mac_bring_window_to_front) (mac_send_window_behind, mac_hide_window, mac_show_window) (mac_collapse_window, mac_front_non_floating_window) (mac_active_non_floating_window, mac_activate_window) (mac_move_window_structure, mac_move_window, mac_size_window) (mac_get_global_mouse, mac_is_window_toolbar_visible): New defines. --- src/macgui.h | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/src/macgui.h b/src/macgui.h index b4c013f0dfa..1f4e454c714 100644 --- a/src/macgui.h +++ b/src/macgui.h @@ -71,7 +71,7 @@ typedef unsigned long Time; #undef Z #define Z (current_buffer->text->z) #else /* not HAVE_CARBON */ -#include /* for WindowRef */ +#include /* for WindowRef */ #include /* for GWorldPtr */ #include /* for ThemeCursor */ #include @@ -125,6 +125,28 @@ typedef unsigned long Time; #endif typedef WindowRef Window; +#if TARGET_API_MAC_CARBON +typedef ScrapRef Selection; +#else +typedef int Selection; +#endif +#define mac_set_window_title SetWindowTitleWithCFString +#define mac_set_window_modified SetWindowModified +#define mac_is_window_visible IsWindowVisible +#define mac_is_window_collapsed IsWindowCollapsed +#define mac_bring_window_to_front BringToFront +#define mac_send_window_behind SendBehind +#define mac_hide_window HideWindow +#define mac_show_window ShowWindow +#define mac_collapse_window CollapseWindow +#define mac_front_non_floating_window FrontNonFloatingWindow +#define mac_active_non_floating_window ActiveNonFloatingWindow +#define mac_activate_window ActivateWindow +#define mac_move_window_structure MoveWindowStructure +#define mac_move_window MoveWindow +#define mac_size_window SizeWindow +#define mac_get_global_mouse GetGlobalMouse +#define mac_is_window_toolbar_visible IsWindowToolbarVisible typedef GWorldPtr Pixmap; #define Cursor ThemeCursor @@ -361,6 +383,97 @@ typedef struct { (nr).right = ((nr).left + (width)), \ (nr).bottom = ((nr).top + (height))) +/* Definitions copied from lwlib.h */ + +typedef void * XtPointer; + +enum button_type +{ + BUTTON_TYPE_NONE, + BUTTON_TYPE_TOGGLE, + BUTTON_TYPE_RADIO +}; + +/* This structure is based on the one in ../lwlib/lwlib.h, modified + for Mac OS. */ +typedef struct _widget_value +{ + /* name of widget */ + Lisp_Object lname; + char* name; + /* value (meaning depend on widget type) */ + char* value; + /* keyboard equivalent. no implications for XtTranslations */ + Lisp_Object lkey; + char* key; + /* Help string or nil if none. + GC finds this string through the frame's menu_bar_vector + or through menu_items. */ + Lisp_Object help; + /* true if enabled */ + Boolean enabled; + /* true if selected */ + Boolean selected; + /* The type of a button. */ + enum button_type button_type; + /* true if menu title */ + Boolean title; +#if 0 + /* true if was edited (maintained by get_value) */ + Boolean edited; + /* true if has changed (maintained by lw library) */ + change_type change; + /* true if this widget itself has changed, + but not counting the other widgets found in the `next' field. */ + change_type this_one_change; +#endif + /* Contents of the sub-widgets, also selected slot for checkbox */ + struct _widget_value* contents; + /* data passed to callback */ + XtPointer call_data; + /* next one in the list */ + struct _widget_value* next; +#if 0 + /* slot for the toolkit dependent part. Always initialize to NULL. */ + void* toolkit_data; + /* tell us if we should free the toolkit data slot when freeing the + widget_value itself. */ + Boolean free_toolkit_data; + + /* we resource the widget_value structures; this points to the next + one on the free list if this one has been deallocated. + */ + struct _widget_value *free_list; +#endif +} widget_value; + +#if MAC_OS8 +#define M_APPLE 234 +#define I_ABOUT 1 + +#define EXTRA_STACK_ALLOC (256 * 1024) + +#define ARGV_STRING_LIST_ID 129 +#define RAM_TOO_LARGE_ALERT_ID 129 +#define ABOUT_ALERT_ID 128 +#endif + +#define DIALOG_LEFT_MARGIN (112) +#define DIALOG_TOP_MARGIN (24) +#define DIALOG_RIGHT_MARGIN (24) +#define DIALOG_BOTTOM_MARGIN (20) +#define DIALOG_MIN_INNER_WIDTH (338) +#define DIALOG_MAX_INNER_WIDTH (564) +#define DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE (12) +#define DIALOG_BUTTON_BUTTON_VERTICAL_SPACE (12) +#define DIALOG_BUTTON_MIN_WIDTH (68) +#define DIALOG_TEXT_MIN_HEIGHT (50) +#define DIALOG_TEXT_BUTTONS_VERTICAL_SPACE (10) +#define DIALOG_ICON_WIDTH (64) +#define DIALOG_ICON_HEIGHT (64) +#define DIALOG_ICON_LEFT_MARGIN (24) +#define DIALOG_ICON_TOP_MARGIN (15) + #endif /* EMACS_MACGUI_H */ /* arch-tag: 5a0da49a-35e2-418b-a58c-8a55778ae849 From 5aa4098ee2f374fadf0bab8a4382b19a4da4cad6 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:58:19 +0000 Subject: [PATCH 09/56] [!TARGET_API_MAC_CARBON]: Move includes to mactoolbox.c. (enum mac_menu_kind): Move enum to mactoolbox.c. (min_menu_id): Move variable to mactoolbox.c. (quit_dialog_event_loop) [TARGET_API_MAC_CARBON]: Likewise. (DIALOG_WINDOW_RESOURCE): Move define to mactoolbox.c. (DIALOG_BUTTON_COMMAND_ID_OFFSET, DIALOG_BUTTON_COMMAND_ID_P) (DIALOG_BUTTON_COMMAND_ID_VALUE, DIALOG_BUTTON_MAKE_COMMAND_ID) [TARGET_API_MAC_CARBON]: Likewise. (XtPointer): Move typedef to macgui.h. (enum button_type): Move enum to macgui.h. (widget_value): Move typedef to macgui.h. (DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN, DIALOG_RIGHT_MARGIN) (DIALOG_BOTTOM_MARGIN, DIALOG_MIN_INNER_WIDTH, DIALOG_MAX_INNER_WIDTH) (DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE) (DIALOG_BUTTON_BUTTON_VERTICAL_SPACE, DIALOG_BUTTON_MIN_WIDTH) (DIALOG_TEXT_MIN_HEIGHT, DIALOG_TEXT_BUTTONS_VERTICAL_SPACE) (DIALOG_ICON_WIDTH, DIALOG_ICON_HEIGHT, DIALOG_ICON_LEFT_MARGIN) (DIALOG_ICON_TOP_MARGIN): Move defines to macgui.h. (popup_activated_flag): Make variable non-static. (x_activate_menubar, install_menu_quit_handler, pop_down_menu) (add_menu_item, fill_menu, dispose_menus): Move functions to mactoolbox.c. (restore_show_help_function, menu_target_item_handler) (install_menu_target_item_handler, mac_handle_dialog_event) (install_dialog_event_handler, pop_down_dialog, create_and_show_dialog) [TARGET_API_MAC_CARBON]: Likewise. (menu_quit_handler) [MAC_OS_X_VERSION_MAX_ALLOWED >= 1030]: Likewise. (mac_dialog) [!TARGET_API_MAC_CARBON]: Likewise. (find_and_call_menu_selection, name_is_separator): Make function non-static. (Vshow_help_function, timer_check) [TARGET_API_MAC_CARBON]: Move extern to mactoolbox.c. (set_frame_menubar): Don't call install_menu_quit_handler. (menu_item_selection): New variable. (mac_menu_show): Use create_and_show_popup_menu. (create_and_show_dialog) [TARGET_API_MAC_CARBON]: Don't return selection but set variable menu_item_selection. All uses changed. (mac_fill_menubar): Rename from fill_menubar. All uses changed. Call install_menu_quit_handler. Move to mactoolbox.c. --- src/macmenu.c | 1323 +------------------------------------------------ 1 file changed, 14 insertions(+), 1309 deletions(-) diff --git a/src/macmenu.c b/src/macmenu.c index 591010a4d65..153969f7efd 100644 --- a/src/macmenu.c +++ b/src/macmenu.c @@ -36,20 +36,6 @@ Boston, MA 02110-1301, USA. */ #include "charset.h" #include "coding.h" -#if !TARGET_API_MAC_CARBON -#include -#include -#include -#include -#include -#include -#include -#include -#if defined (__MRC__) || (__MSL__ >= 0x6000) -#include -#endif -#endif /* not TARGET_API_MAC_CARBON */ - /* This may include sys/types.h, and that somehow loses if this is not done before the other system files. */ #include "macterm.h" @@ -62,21 +48,6 @@ Boston, MA 02110-1301, USA. */ #include "dispextern.h" -enum mac_menu_kind { /* Menu ID range */ - MAC_MENU_APPLE, /* 0 (Reserved by Apple) */ - MAC_MENU_MENU_BAR, /* 1 .. 233 */ - MAC_MENU_M_APPLE, /* 234 (== M_APPLE) */ - MAC_MENU_POPUP, /* 235 */ - MAC_MENU_DRIVER, /* 236 .. 255 (Reserved) */ - MAC_MENU_MENU_BAR_SUB, /* 256 .. 16383 */ - MAC_MENU_POPUP_SUB, /* 16384 .. 32767 */ - MAC_MENU_END /* 32768 */ -}; - -static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768}; - -#define DIALOG_WINDOW_RESOURCE 130 - #if TARGET_API_MAC_CARBON #define HAVE_DIALOGS 1 #endif @@ -84,69 +55,6 @@ static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768}; #undef HAVE_MULTILINGUAL_MENU /******************************************************************/ -/* Definitions copied from lwlib.h */ - -typedef void * XtPointer; - -enum button_type -{ - BUTTON_TYPE_NONE, - BUTTON_TYPE_TOGGLE, - BUTTON_TYPE_RADIO -}; - -/* This structure is based on the one in ../lwlib/lwlib.h, modified - for Mac OS. */ -typedef struct _widget_value -{ - /* name of widget */ - Lisp_Object lname; - char* name; - /* value (meaning depend on widget type) */ - char* value; - /* keyboard equivalent. no implications for XtTranslations */ - Lisp_Object lkey; - char* key; - /* Help string or nil if none. - GC finds this string through the frame's menu_bar_vector - or through menu_items. */ - Lisp_Object help; - /* true if enabled */ - Boolean enabled; - /* true if selected */ - Boolean selected; - /* The type of a button. */ - enum button_type button_type; - /* true if menu title */ - Boolean title; -#if 0 - /* true if was edited (maintained by get_value) */ - Boolean edited; - /* true if has changed (maintained by lw library) */ - change_type change; - /* true if this widget itself has changed, - but not counting the other widgets found in the `next' field. */ - change_type this_one_change; -#endif - /* Contents of the sub-widgets, also selected slot for checkbox */ - struct _widget_value* contents; - /* data passed to callback */ - XtPointer call_data; - /* next one in the list */ - struct _widget_value* next; -#if 0 - /* slot for the toolkit dependent part. Always initialize to NULL. */ - void* toolkit_data; - /* tell us if we should free the toolkit data slot when freeing the - widget_value itself. */ - Boolean free_toolkit_data; - - /* we resource the widget_value structures; this points to the next - one on the free list if this one has been deallocated. - */ - struct _widget_value *free_list; -#endif -} widget_value; /* Assumed by other routines to zero area returned. */ #define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\ @@ -198,12 +106,6 @@ static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object, static void list_of_panes P_ ((Lisp_Object)); static void list_of_items P_ ((Lisp_Object)); -static void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object, - void *)); -static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int)); -static void fill_menubar P_ ((widget_value *, int)); -static void dispose_menus P_ ((enum mac_menu_kind, int)); - /* This holds a Lisp vector that holds the results of decoding the keymaps or alist-of-alists that specify a menu. @@ -260,7 +162,7 @@ static int menu_items_n_panes; static int menu_items_submenu_depth; /* Nonzero means a menu is currently active. */ -static int popup_activated_flag; +int popup_activated_flag; /* This is set nonzero after the user activates the menu bar, and set to zero again after the menu bars are redisplayed by prepare_menu_bar. @@ -880,32 +782,6 @@ no quit occurs and `x-popup-menu' returns nil. */) #ifdef HAVE_MENUS -/* Regard ESC and C-g as Cancel even without the Cancel button. */ - -#if 0 /* defined (MAC_OSX) */ -static Boolean -mac_dialog_modal_filter (dialog, event, item_hit) - DialogRef dialog; - EventRecord *event; - DialogItemIndex *item_hit; -{ - Boolean result; - - result = StdFilterProc (dialog, event, item_hit); - if (result == false - && (event->what == keyDown || event->what == autoKey) - && ((event->message & charCodeMask) == kEscapeCharCode - || mac_quit_char_key_p (event->modifiers, - (event->message & keyCodeMask) >> 8))) - { - *item_hit = kStdCancelItemIndex; - return true; - } - - return result; -} -#endif - DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, doc: /* Pop up a dialog box and return user's selection. POSITION specifies which frame to use. @@ -991,101 +867,6 @@ for instance using the window manager, then this produces a quit and but I don't want to make one now. */ CHECK_WINDOW (window); -#if 0 /* defined (MAC_OSX) */ - /* Special treatment for Fmessage_box, Fyes_or_no_p, and Fy_or_n_p. */ - if (EQ (position, Qt) - && STRINGP (Fcar (contents)) - && ((!NILP (Fequal (XCDR (contents), - Fcons (Fcons (build_string ("OK"), Qt), Qnil))) - && EQ (header, Qt)) - || (!NILP (Fequal (XCDR (contents), - Fcons (Fcons (build_string ("Yes"), Qt), - Fcons (Fcons (build_string ("No"), Qnil), - Qnil)))) - && NILP (header)))) - { - OSStatus err = noErr; - AlertStdCFStringAlertParamRec param; - CFStringRef error_string, explanation_string; - DialogRef alert; - DialogItemIndex item_hit; - Lisp_Object tem; - - /* Force a redisplay before showing the dialog. If a frame is - created just before showing the dialog, its contents may not - have been fully drawn. */ - Fredisplay (Qt); - - tem = Fstring_match (concat3 (build_string ("\\("), - call0 (intern ("sentence-end")), - build_string ("\\)\n")), - XCAR (contents), Qnil); - BLOCK_INPUT; - if (NILP (tem)) - { - error_string = cfstring_create_with_string (XCAR (contents)); - if (error_string == NULL) - err = memFullErr; - explanation_string = NULL; - } - else - { - tem = Fmatch_end (make_number (1)); - error_string = - cfstring_create_with_string (Fsubstring (XCAR (contents), - make_number (0), tem)); - if (error_string == NULL) - err = memFullErr; - else - { - XSETINT (tem, XINT (tem) + 1); - explanation_string = - cfstring_create_with_string (Fsubstring (XCAR (contents), - tem, Qnil)); - if (explanation_string == NULL) - { - CFRelease (error_string); - err = memFullErr; - } - } - } - if (err == noErr) - err = GetStandardAlertDefaultParams (¶m, - kStdCFStringAlertVersionOne); - if (err == noErr) - { - param.movable = true; - param.position = kWindowAlertPositionParentWindow; - if (NILP (header)) - { - param.defaultText = CFSTR ("Yes"); - param.otherText = CFSTR ("No"); -#if 0 - param.cancelText = CFSTR ("Cancel"); - param.cancelButton = kAlertStdAlertCancelButton; -#endif - } - err = CreateStandardAlert (kAlertNoteAlert, error_string, - explanation_string, ¶m, &alert); - CFRelease (error_string); - if (explanation_string) - CFRelease (explanation_string); - } - if (err == noErr) - err = RunStandardAlert (alert, mac_dialog_modal_filter, &item_hit); - UNBLOCK_INPUT; - - if (err == noErr) - { - if (item_hit == kStdCancelItemIndex) - Fsignal (Qquit, Qnil); - else if (item_hit == kStdOkItemIndex) - return Qt; - else - return Qnil; - } - } -#endif #ifndef HAVE_DIALOGS /* Display a menu with these alternatives in the middle of frame F. */ @@ -1125,66 +906,12 @@ for instance using the window manager, then this produces a quit and #endif /* HAVE_DIALOGS */ } -/* Activate the menu bar of frame F. - This is called from keyboard.c when it gets the - MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue. - - To activate the menu bar, we use the button-press event location - that was saved in saved_menu_event_location. - - But first we recompute the menu bar contents (the whole tree). - - The reason for saving the button event until here, instead of - passing it to the toolkit right away, is that we can safely - execute Lisp code. */ - -void -x_activate_menubar (f) - FRAME_PTR f; -{ - SInt32 menu_choice; - SInt16 menu_id, menu_item; - extern Point saved_menu_event_location; - - set_frame_menubar (f, 0, 1); - BLOCK_INPUT; - - popup_activated_flag = 1; - menu_choice = MenuSelect (saved_menu_event_location); - popup_activated_flag = 0; - menu_id = HiWord (menu_choice); - menu_item = LoWord (menu_choice); - -#if !TARGET_API_MAC_CARBON - if (menu_id == min_menu_id[MAC_MENU_M_APPLE]) - do_apple_menu (menu_item); - else -#endif - if (menu_id) - { - MenuRef menu = GetMenuRef (menu_id); - - if (menu) - { - UInt32 refcon; - - GetMenuItemRefCon (menu, menu_item, &refcon); - find_and_call_menu_selection (f, f->menu_bar_items_used, - f->menu_bar_vector, (void *) refcon); - } - } - - HiliteMenu (0); - - UNBLOCK_INPUT; -} - /* Find the menu selection and store it in the keyboard buffer. F is the frame the menu is on. MENU_BAR_ITEMS_USED is the length of VECTOR. VECTOR is an array of menu events for the whole menu. */ -static void +void find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data) FRAME_PTR f; int menu_bar_items_used; @@ -1577,141 +1304,6 @@ update_submenu_strings (first_wv) } -#if TARGET_API_MAC_CARBON -extern Lisp_Object Vshow_help_function; - -static Lisp_Object -restore_show_help_function (old_show_help_function) - Lisp_Object old_show_help_function; -{ - Vshow_help_function = old_show_help_function; - - return Qnil; -} - -static pascal OSStatus -menu_target_item_handler (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - OSStatus err; - MenuRef menu; - MenuItemIndex menu_item; - Lisp_Object help; - GrafPtr port; - int specpdl_count = SPECPDL_INDEX (); - - /* Don't be bothered with the overflowed toolbar items menu. */ - if (!popup_activated ()) - return eventNotHandledErr; - - err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef, - NULL, sizeof (MenuRef), NULL, &menu); - if (err == noErr) - err = GetEventParameter (event, kEventParamMenuItemIndex, - typeMenuItemIndex, NULL, - sizeof (MenuItemIndex), NULL, &menu_item); - if (err == noErr) - err = GetMenuItemProperty (menu, menu_item, - MAC_EMACS_CREATOR_CODE, 'help', - sizeof (Lisp_Object), NULL, &help); - if (err != noErr) - help = Qnil; - - /* Temporarily bind Vshow_help_function to Qnil because we don't - want tooltips during menu tracking. */ - record_unwind_protect (restore_show_help_function, Vshow_help_function); - Vshow_help_function = Qnil; - GetPort (&port); - show_help_echo (help, Qnil, Qnil, Qnil, 1); - SetPort (port); - unbind_to (specpdl_count, Qnil); - - return err == noErr ? noErr : eventNotHandledErr; -} - -OSStatus -install_menu_target_item_handler () -{ - static const EventTypeSpec specs[] = - {{kEventClassMenu, kEventMenuTargetItem}}; - - return InstallApplicationEventHandler (NewEventHandlerUPP - (menu_target_item_handler), - GetEventTypeCount (specs), - specs, NULL, NULL); -} -#endif /* TARGET_API_MAC_CARBON */ - -/* Event handler function that pops down a menu on C-g. We can only pop - down menus if CancelMenuTracking is present (OSX 10.3 or later). */ - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 -static pascal OSStatus -menu_quit_handler (nextHandler, theEvent, userData) - EventHandlerCallRef nextHandler; - EventRef theEvent; - void* userData; -{ - OSStatus err; - UInt32 keyCode; - UInt32 keyModifiers; - - err = GetEventParameter (theEvent, kEventParamKeyCode, - typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); - - if (err == noErr) - err = GetEventParameter (theEvent, kEventParamKeyModifiers, - typeUInt32, NULL, sizeof(UInt32), - NULL, &keyModifiers); - - if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode)) - { - MenuRef menu = userData != 0 - ? (MenuRef)userData : AcquireRootMenu (); - - CancelMenuTracking (menu, true, 0); - if (!userData) ReleaseMenu (menu); - return noErr; - } - - return CallNextEventHandler (nextHandler, theEvent); -} -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */ - -/* Add event handler to all menus that belong to KIND so we can detect - C-g. ROOT_MENU is the root menu of the tracking session to dismiss - when C-g is detected. NULL means the menu bar. If - CancelMenuTracking isn't available, do nothing. */ - -static void -install_menu_quit_handler (kind, root_menu) - enum mac_menu_kind kind; - MenuRef root_menu; -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 - static const EventTypeSpec typesList[] = - {{kEventClassKeyboard, kEventRawKeyDown}}; - int id; - -#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020 - if (CancelMenuTracking == NULL) - return; -#endif - for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++) - { - MenuRef menu = GetMenuRef (id); - - if (menu == NULL) - break; - InstallMenuEventHandler (menu, menu_quit_handler, - GetEventTypeCount (typesList), - typesList, root_menu, NULL); - } -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */ -} - /* Set the contents of the menubar widgets of frame F. The argument FIRST_TIME is currently ignored; it is set the first time this is called, from initialize_frame_menubar. */ @@ -1947,11 +1539,8 @@ set_frame_menubar (f, first_time, deep_p) /* Non-null value to indicate menubar has already been "created". */ f->output_data.mac->menubar_widget = 1; - fill_menubar (first_wv->contents, deep_p); + mac_fill_menubar (first_wv->contents, deep_p); - /* Add event handler so we can detect C-g. */ - install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL); - install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL); free_menubar_widget_value_tree (first_wv); UNBLOCK_INPUT; @@ -1968,29 +1557,8 @@ free_frame_menubar (f) } -static Lisp_Object -pop_down_menu (arg) - Lisp_Object arg; -{ - struct Lisp_Save_Value *p = XSAVE_VALUE (arg); - FRAME_PTR f = p->pointer; - MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]); - - BLOCK_INPUT; - - /* Must reset this manually because the button release event is not - passed to Emacs event loop. */ - FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0; - - /* delete all menus */ - dispose_menus (MAC_MENU_POPUP_SUB, 0); - DeleteMenu (min_menu_id[MAC_MENU_POPUP]); - DisposeMenu (menu); - - UNBLOCK_INPUT; - - return Qnil; -} +/* The item selected in the popup menu. */ +int menu_item_selection; /* Mac_menu_show actually displays a menu using the panes and items in menu_items and returns the value selected from it; we assume input @@ -2018,9 +1586,6 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) char **error; { int i; - int menu_item_choice; - UInt32 menu_item_selection; - MenuRef menu; widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; widget_value **submenu_stack = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); @@ -2029,7 +1594,6 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) int submenu_depth = 0; int first_pane; - int specpdl_count = SPECPDL_INDEX (); *error = NULL; @@ -2215,45 +1779,14 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) first_wv->contents = wv_title; } - /* Actually create the menu. */ - menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p"); - InsertMenu (menu, -1); - fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB, - min_menu_id[MAC_MENU_POPUP_SUB]); - - /* Free the widget_value objects we used to specify the - contents. */ - free_menubar_widget_value_tree (first_wv); - - /* Adjust coordinates to be root-window-relative. */ - x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); - y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); - /* No selection has been chosen yet. */ menu_item_selection = 0; - record_unwind_protect (pop_down_menu, make_save_value (f, 0)); + /* Actually create and show the menu until popped down. */ + create_and_show_popup_menu (f, first_wv, x, y, for_click); - /* Add event handler so we can detect C-g. */ - install_menu_quit_handler (MAC_MENU_POPUP, menu); - install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu); - - /* Display the menu. */ - popup_activated_flag = 1; - menu_item_choice = PopUpMenuSelect (menu, y, x, 0); - popup_activated_flag = 0; - - /* Get the refcon to find the correct item */ - if (menu_item_choice) - { - MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice)); - - if (sel_menu) - GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice), - &menu_item_selection); - } - - unbind_to (specpdl_count, Qnil); + /* Free the widget_value objects we used to specify the contents. */ + free_menubar_widget_value_tree (first_wv); /* Find the selected item, and its pane, to return the proper value. */ @@ -2320,582 +1853,6 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error) #ifdef HAVE_DIALOGS /* Construct native Mac OS dialog based on widget_value tree. */ -#if TARGET_API_MAC_CARBON - -#define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0' -#define DIALOG_BUTTON_COMMAND_ID_P(id) \ - (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET) -#define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \ - ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET) -#define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \ - ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET) - -extern EMACS_TIME timer_check P_ ((int)); -static int quit_dialog_event_loop; - -static pascal OSStatus -mac_handle_dialog_event (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - OSStatus err, result = eventNotHandledErr; - WindowRef window = (WindowRef) data; - - switch (GetEventClass (event)) - { - case kEventClassCommand: - { - HICommand command; - - err = GetEventParameter (event, kEventParamDirectObject, - typeHICommand, NULL, sizeof (HICommand), - NULL, &command); - if (err == noErr) - if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID)) - { - SetWRefCon (window, command.commandID); - quit_dialog_event_loop = 1; - break; - } - - result = CallNextEventHandler (next_handler, event); - } - break; - - case kEventClassKeyboard: - { - OSStatus result; - char char_code; - - result = CallNextEventHandler (next_handler, event); - if (result != eventNotHandledErr) - break; - - err = GetEventParameter (event, kEventParamKeyMacCharCodes, - typeChar, NULL, sizeof (char), - NULL, &char_code); - if (err == noErr) - switch (char_code) - { - case kEscapeCharCode: - quit_dialog_event_loop = 1; - break; - - default: - { - UInt32 modifiers, key_code; - - err = GetEventParameter (event, kEventParamKeyModifiers, - typeUInt32, NULL, sizeof (UInt32), - NULL, &modifiers); - if (err == noErr) - err = GetEventParameter (event, kEventParamKeyCode, - typeUInt32, NULL, sizeof (UInt32), - NULL, &key_code); - if (err == noErr) - if (mac_quit_char_key_p (modifiers, key_code)) - quit_dialog_event_loop = 1; - } - break; - } - } - break; - - default: - abort (); - } - - if (quit_dialog_event_loop) - { - err = QuitEventLoop (GetCurrentEventLoop ()); - if (err == noErr) - result = noErr; - } - - return result; -} - -static OSStatus -install_dialog_event_handler (window) - WindowRef window; -{ - static const EventTypeSpec specs[] = - {{kEventClassCommand, kEventCommandProcess}, - {kEventClassKeyboard, kEventRawKeyDown}}; - static EventHandlerUPP handle_dialog_eventUPP = NULL; - - if (handle_dialog_eventUPP == NULL) - handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event); - return InstallWindowEventHandler (window, handle_dialog_eventUPP, - GetEventTypeCount (specs), specs, - window, NULL); -} - -#define DIALOG_LEFT_MARGIN (112) -#define DIALOG_TOP_MARGIN (24) -#define DIALOG_RIGHT_MARGIN (24) -#define DIALOG_BOTTOM_MARGIN (20) -#define DIALOG_MIN_INNER_WIDTH (338) -#define DIALOG_MAX_INNER_WIDTH (564) -#define DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE (12) -#define DIALOG_BUTTON_BUTTON_VERTICAL_SPACE (12) -#define DIALOG_BUTTON_MIN_WIDTH (68) -#define DIALOG_TEXT_MIN_HEIGHT (50) -#define DIALOG_TEXT_BUTTONS_VERTICAL_SPACE (10) -#define DIALOG_ICON_WIDTH (64) -#define DIALOG_ICON_HEIGHT (64) -#define DIALOG_ICON_LEFT_MARGIN (24) -#define DIALOG_ICON_TOP_MARGIN (15) - -static Lisp_Object -pop_down_dialog (arg) - Lisp_Object arg; -{ - struct Lisp_Save_Value *p = XSAVE_VALUE (arg); - WindowRef window = p->pointer; - - BLOCK_INPUT; - - if (popup_activated_flag) - EndAppModalStateForWindow (window); - DisposeWindow (window); - popup_activated_flag = 0; - - UNBLOCK_INPUT; - - return Qnil; -} - -static int -create_and_show_dialog (f, first_wv) - FRAME_PTR f; - widget_value *first_wv; -{ - OSStatus err; - char *dialog_name, *message; - int nb_buttons, first_group_count, i, result = 0; - widget_value *wv; - short buttons_height, text_height, inner_width, inner_height; - Rect empty_rect, *rects; - WindowRef window = NULL; - ControlRef *buttons, default_button = NULL, text; - int specpdl_count = SPECPDL_INDEX (); - - dialog_name = first_wv->name; - nb_buttons = dialog_name[1] - '0'; - first_group_count = nb_buttons - (dialog_name[4] - '0'); - - wv = first_wv->contents; - message = wv->value; - - wv = wv->next; - SetRect (&empty_rect, 0, 0, 0, 0); - - /* Create dialog window. */ - err = CreateNewWindow (kMovableModalWindowClass, - kWindowStandardHandlerAttribute, - &empty_rect, &window); - if (err == noErr) - { - record_unwind_protect (pop_down_dialog, make_save_value (window, 0)); - err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground, - true); - } - if (err == noErr) - err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q' - ? CFSTR ("Question") - : CFSTR ("Information"))); - - /* Create button controls and measure their optimal bounds. */ - if (err == noErr) - { - buttons = alloca (sizeof (ControlRef) * nb_buttons); - rects = alloca (sizeof (Rect) * nb_buttons); - for (i = 0; i < nb_buttons; i++) - { - CFStringRef label = cfstring_create_with_utf8_cstring (wv->value); - - if (label == NULL) - err = memFullErr; - else - { - err = CreatePushButtonControl (window, &empty_rect, - label, &buttons[i]); - CFRelease (label); - } - if (err == noErr) - { - if (!wv->enabled) - { -#ifdef MAC_OSX - err = DisableControl (buttons[i]); -#else - err = DeactivateControl (buttons[i]); -#endif - } - else if (default_button == NULL) - default_button = buttons[i]; - } - if (err == noErr) - { - SInt16 unused; - - rects[i] = empty_rect; - err = GetBestControlRect (buttons[i], &rects[i], &unused); - } - if (err == noErr) - { - UInt32 command_id; - - OffsetRect (&rects[i], -rects[i].left, -rects[i].top); - if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH) - rects[i].right = DIALOG_BUTTON_MIN_WIDTH; - else if (rects[i].right > DIALOG_MAX_INNER_WIDTH) - rects[i].right = DIALOG_MAX_INNER_WIDTH; - - command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data); - err = SetControlCommandID (buttons[i], command_id); - } - if (err != noErr) - break; - wv = wv->next; - } - } - - /* Layout buttons. rects[i] is set relative to the bottom-right - corner of the inner box. */ - if (err == noErr) - { - short bottom, right, max_height, left_align_shift; - - inner_width = DIALOG_MIN_INNER_WIDTH; - bottom = right = max_height = 0; - for (i = 0; i < nb_buttons; i++) - { - if (right - rects[i].right < - inner_width) - { - if (i != first_group_count - && right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH) - inner_width = - (right - rects[i].right); - else - { - bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE; - right = max_height = 0; - } - } - if (max_height < rects[i].bottom) - max_height = rects[i].bottom; - OffsetRect (&rects[i], right - rects[i].right, - bottom - rects[i].bottom); - right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE; - if (i == first_group_count - 1) - right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE; - } - buttons_height = - (bottom - max_height); - - left_align_shift = - (inner_width + rects[nb_buttons - 1].left); - for (i = nb_buttons - 1; i >= first_group_count; i--) - { - if (bottom != rects[i].bottom) - { - left_align_shift = - (inner_width + rects[i].left); - bottom = rects[i].bottom; - } - OffsetRect (&rects[i], left_align_shift, 0); - } - } - - /* Create a static text control and measure its bounds. */ - if (err == noErr) - { - CFStringRef message_string; - Rect bounds; - - message_string = cfstring_create_with_utf8_cstring (message); - if (message_string == NULL) - err = memFullErr; - else - { - ControlFontStyleRec text_style; - - text_style.flags = 0; - SetRect (&bounds, 0, 0, inner_width, 0); - err = CreateStaticTextControl (window, &bounds, message_string, - &text_style, &text); - CFRelease (message_string); - } - if (err == noErr) - { - SInt16 unused; - - bounds = empty_rect; - err = GetBestControlRect (text, &bounds, &unused); - } - if (err == noErr) - { - text_height = bounds.bottom - bounds.top; - if (text_height < DIALOG_TEXT_MIN_HEIGHT) - text_height = DIALOG_TEXT_MIN_HEIGHT; - } - } - - /* Place buttons. */ - if (err == noErr) - { - inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE - + buttons_height); - - for (i = 0; i < nb_buttons; i++) - { - OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width, - DIALOG_TOP_MARGIN + inner_height); - SetControlBounds (buttons[i], &rects[i]); - } - } - - /* Place text. */ - if (err == noErr) - { - Rect bounds; - - SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN, - DIALOG_LEFT_MARGIN + inner_width, - DIALOG_TOP_MARGIN + text_height); - SetControlBounds (text, &bounds); - } - - /* Create the application icon at the upper-left corner. */ - if (err == noErr) - { - ControlButtonContentInfo content; - ControlRef icon; - static const ProcessSerialNumber psn = {0, kCurrentProcess}; -#ifdef MAC_OSX - FSRef app_location; -#else - ProcessInfoRec pinfo; - FSSpec app_spec; -#endif - SInt16 unused; - - content.contentType = kControlContentIconRef; -#ifdef MAC_OSX - err = GetProcessBundleLocation (&psn, &app_location); - if (err == noErr) - err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL, - kIconServicesNormalUsageFlag, - &content.u.iconRef, &unused); -#else - bzero (&pinfo, sizeof (ProcessInfoRec)); - pinfo.processInfoLength = sizeof (ProcessInfoRec); - pinfo.processAppSpec = &app_spec; - err = GetProcessInformation (&psn, &pinfo); - if (err == noErr) - err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused); -#endif - if (err == noErr) - { - Rect bounds; - - SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN, - DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH, - DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT); - err = CreateIconControl (window, &bounds, &content, true, &icon); - ReleaseIconRef (content.u.iconRef); - } - } - - /* Show the dialog window and run event loop. */ - if (err == noErr) - if (default_button) - err = SetWindowDefaultButton (window, default_button); - if (err == noErr) - err = install_dialog_event_handler (window); - if (err == noErr) - { - SizeWindow (window, - DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN, - DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN, - true); - err = RepositionWindow (window, FRAME_MAC_WINDOW (f), - kWindowAlertPositionOnParentWindow); - } - if (err == noErr) - { - SetWRefCon (window, 0); - ShowWindow (window); - BringToFront (window); - popup_activated_flag = 1; - err = BeginAppModalStateForWindow (window); - } - if (err == noErr) - { - EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget (); - - quit_dialog_event_loop = 0; - while (1) - { - EMACS_TIME next_time = timer_check (1); - long secs = EMACS_SECS (next_time); - long usecs = EMACS_USECS (next_time); - EventTimeout timeout; - EventRef event; - - if (secs < 0 || (secs == 0 && usecs == 0)) - { - /* Sometimes timer_check returns -1 (no timers) even if - there are timers. So do a timeout anyway. */ - secs = 1; - usecs = 0; - } - - timeout = (secs * kEventDurationSecond - + usecs * kEventDurationMicrosecond); - err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue, - &event); - if (err == noErr) - { - SendEventToEventTarget (event, toolbox_dispatcher); - ReleaseEvent (event); - } -#if 0 /* defined (MAC_OSX) */ - else if (err != eventLoopTimedOutErr) - { - if (err == eventLoopQuitErr) - err = noErr; - break; - } -#else - /* The return value of ReceiveNextEvent seems to be - unreliable. Use our own global variable instead. */ - if (quit_dialog_event_loop) - { - err = noErr; - break; - } -#endif - } - } - if (err == noErr) - { - UInt32 command_id = GetWRefCon (window); - - if (DIALOG_BUTTON_COMMAND_ID_P (command_id)) - result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id); - } - - unbind_to (specpdl_count, Qnil); - - return result; -} -#else /* not TARGET_API_MAC_CARBON */ -static int -mac_dialog (widget_value *wv) -{ - char *dialog_name; - char *prompt; - char **button_labels; - UInt32 *ref_cons; - int nb_buttons; - int left_count; - int i; - int dialog_width; - Rect rect; - WindowRef window_ptr; - ControlRef ch; - int left; - EventRecord event_record; - SInt16 part_code; - int control_part_code; - Point mouse; - - dialog_name = wv->name; - nb_buttons = dialog_name[1] - '0'; - left_count = nb_buttons - (dialog_name[4] - '0'); - button_labels = (char **) alloca (sizeof (char *) * nb_buttons); - ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons); - - wv = wv->contents; - prompt = (char *) alloca (strlen (wv->value) + 1); - strcpy (prompt, wv->value); - c2pstr (prompt); - - wv = wv->next; - for (i = 0; i < nb_buttons; i++) - { - button_labels[i] = wv->value; - button_labels[i] = (char *) alloca (strlen (wv->value) + 1); - strcpy (button_labels[i], wv->value); - c2pstr (button_labels[i]); - ref_cons[i] = (UInt32) wv->call_data; - wv = wv->next; - } - - window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1); - - SetPortWindowPort (window_ptr); - - TextFont (0); - /* Left and right margins in the dialog are 13 pixels each.*/ - dialog_width = 14; - /* Calculate width of dialog box: 8 pixels on each side of the text - label in each button, 12 pixels between buttons. */ - for (i = 0; i < nb_buttons; i++) - dialog_width += StringWidth (button_labels[i]) + 16 + 12; - - if (left_count != 0 && nb_buttons - left_count != 0) - dialog_width += 12; - - dialog_width = max (dialog_width, StringWidth (prompt) + 26); - - SizeWindow (window_ptr, dialog_width, 78, 0); - ShowWindow (window_ptr); - - SetPortWindowPort (window_ptr); - - TextFont (0); - - MoveTo (13, 29); - DrawString (prompt); - - left = 13; - for (i = 0; i < nb_buttons; i++) - { - int button_width = StringWidth (button_labels[i]) + 16; - SetRect (&rect, left, 45, left + button_width, 65); - ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0, - kControlPushButtonProc, ref_cons[i]); - left += button_width + 12; - if (i == left_count - 1) - left += 12; - } - - i = 0; - while (!i) - { - if (WaitNextEvent (mDownMask, &event_record, 10, NULL)) - if (event_record.what == mouseDown) - { - part_code = FindWindow (event_record.where, &window_ptr); - if (part_code == inContent) - { - mouse = event_record.where; - GlobalToLocal (&mouse); - control_part_code = FindControl (mouse, window_ptr, &ch); - if (control_part_code == kControlButtonPart) - if (TrackControl (ch, mouse, NULL)) - i = GetControlReference (ch); - } - } - } - - DisposeWindow (window_ptr); - - return i; -} -#endif /* not TARGET_API_MAC_CARBON */ - static char * button_names [] = { "button1", "button2", "button3", "button4", "button5", "button6", "button7", "button8", "button9", "button10" }; @@ -2909,7 +1866,6 @@ mac_dialog_show (f, keymaps, title, header, error_name) { int i, nb_buttons=0; char dialog_name[6]; - int menu_item_selection; widget_value *wv, *first_wv = 0, *prev_wv = 0; @@ -3026,6 +1982,9 @@ mac_dialog_show (f, keymaps, title, header, error_name) first_wv = wv; } + /* No selection has been chosen yet. */ + menu_item_selection = 0; + /* Force a redisplay before showing the dialog. If a frame is created just before showing the dialog, its contents may not have been fully drawn. */ @@ -3033,7 +1992,7 @@ mac_dialog_show (f, keymaps, title, header, error_name) /* Actually create the dialog. */ #if TARGET_API_MAC_CARBON - menu_item_selection = create_and_show_dialog (f, first_wv); + create_and_show_dialog (f, first_wv); #else menu_item_selection = mac_dialog (first_wv); #endif @@ -3093,7 +2052,7 @@ mac_dialog_show (f, keymaps, title, header, error_name) /* Is this item a separator? */ -static int +int name_is_separator (name) const char *name; { @@ -3106,260 +2065,6 @@ name_is_separator (name) them like normal separators. */ return (*name == '\0' || start + 2 == name); } - -static void -add_menu_item (menu, pos, wv) - MenuRef menu; - int pos; - widget_value *wv; -{ -#if TARGET_API_MAC_CARBON - CFStringRef item_name; -#else - Str255 item_name; -#endif - - if (name_is_separator (wv->name)) - AppendMenu (menu, "\p-"); - else - { - AppendMenu (menu, "\pX"); - -#if TARGET_API_MAC_CARBON - item_name = cfstring_create_with_utf8_cstring (wv->name); - - if (wv->key != NULL) - { - CFStringRef name, key; - - name = item_name; - key = cfstring_create_with_utf8_cstring (wv->key); - item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"), - name, key); - CFRelease (name); - CFRelease (key); - } - - SetMenuItemTextWithCFString (menu, pos, item_name); - CFRelease (item_name); - - if (wv->enabled) - EnableMenuItem (menu, pos); - else - DisableMenuItem (menu, pos); - - if (STRINGP (wv->help)) - SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help', - sizeof (Lisp_Object), &wv->help); -#else /* ! TARGET_API_MAC_CARBON */ - item_name[sizeof (item_name) - 1] = '\0'; - strncpy (item_name, wv->name, sizeof (item_name) - 1); - if (wv->key != NULL) - { - int len = strlen (item_name); - - strncpy (item_name + len, " ", sizeof (item_name) - 1 - len); - len = strlen (item_name); - strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len); - } - c2pstr (item_name); - SetMenuItemText (menu, pos, item_name); - - if (wv->enabled) - EnableItem (menu, pos); - else - DisableItem (menu, pos); -#endif /* ! TARGET_API_MAC_CARBON */ - - /* Draw radio buttons and tickboxes. */ - if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE || - wv->button_type == BUTTON_TYPE_RADIO)) - SetItemMark (menu, pos, checkMark); - else - SetItemMark (menu, pos, noMark); - - SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data); - } -} - -/* Construct native Mac OS menu based on widget_value tree. */ - -static int -fill_menu (menu, wv, kind, submenu_id) - MenuRef menu; - widget_value *wv; - enum mac_menu_kind kind; - int submenu_id; -{ - int pos; - - for (pos = 1; wv != NULL; wv = wv->next, pos++) - { - add_menu_item (menu, pos, wv); - if (wv->contents && submenu_id < min_menu_id[kind + 1]) - { - MenuRef submenu = NewMenu (submenu_id, "\pX"); - - InsertMenu (submenu, -1); -#if TARGET_API_MAC_CARBON - SetMenuItemHierarchicalMenu (menu, pos, submenu); -#else - SetMenuItemHierarchicalID (menu, pos, submenu_id); -#endif - submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1); - } - } - - return submenu_id; -} - -/* Construct native Mac OS menubar based on widget_value tree. */ - -static void -fill_menubar (wv, deep_p) - widget_value *wv; - int deep_p; -{ - int id, submenu_id; -#if !TARGET_API_MAC_CARBON - int title_changed_p = 0; -#endif - - /* Clean up the menu bar when filled by the entire menu trees. */ - if (deep_p) - { - dispose_menus (MAC_MENU_MENU_BAR, 0); - dispose_menus (MAC_MENU_MENU_BAR_SUB, 0); -#if !TARGET_API_MAC_CARBON - title_changed_p = 1; -#endif - } - - /* Fill menu bar titles and submenus. Reuse the existing menu bar - titles as much as possible to minimize redraw (if !deep_p). */ - submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB]; - for (id = min_menu_id[MAC_MENU_MENU_BAR]; - wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1]; - wv = wv->next, id++) - { - OSStatus err = noErr; - MenuRef menu; -#if TARGET_API_MAC_CARBON - CFStringRef title; - - title = CFStringCreateWithCString (NULL, wv->name, - kCFStringEncodingMacRoman); -#else - Str255 title; - - strncpy (title, wv->name, 255); - title[255] = '\0'; - c2pstr (title); -#endif - - menu = GetMenuRef (id); - if (menu) - { -#if TARGET_API_MAC_CARBON - CFStringRef old_title; - - err = CopyMenuTitleAsCFString (menu, &old_title); - if (err == noErr) - { - if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo) - { -#ifdef MAC_OSX - if (id + 1 == min_menu_id[MAC_MENU_MENU_BAR + 1] - || GetMenuRef (id + 1) == NULL) - { - /* This is a workaround for Mac OS X 10.5 where - just calling SetMenuTitleWithCFString fails - to change the title of the last (Help) menu - in the menu bar. */ - DeleteMenu (id); - DisposeMenu (menu); - menu = NULL; - } - else -#endif /* MAC_OSX */ - err = SetMenuTitleWithCFString (menu, title); - } - CFRelease (old_title); - } - else - err = SetMenuTitleWithCFString (menu, title); -#else /* !TARGET_API_MAC_CARBON */ - if (!EqualString (title, (*menu)->menuData, false, false)) - { - DeleteMenu (id); - DisposeMenu (menu); - menu = NewMenu (id, title); - InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0); - title_changed_p = 1; - } -#endif /* !TARGET_API_MAC_CARBON */ - } - - if (!menu) - { -#if TARGET_API_MAC_CARBON - err = CreateNewMenu (id, 0, &menu); - if (err == noErr) - err = SetMenuTitleWithCFString (menu, title); -#else - menu = NewMenu (id, title); -#endif - if (err == noErr) - { - InsertMenu (menu, 0); -#if !TARGET_API_MAC_CARBON - title_changed_p = 1; -#endif - } - } -#if TARGET_API_MAC_CARBON - CFRelease (title); -#endif - - if (err == noErr) - if (wv->contents) - submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB, - submenu_id); - } - - if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id)) - { - dispose_menus (MAC_MENU_MENU_BAR, id); -#if !TARGET_API_MAC_CARBON - title_changed_p = 1; -#endif - } - -#if !TARGET_API_MAC_CARBON - if (title_changed_p) - InvalMenuBar (); -#endif -} - -/* Dispose of menus that belong to KIND, and remove them from the menu - list. ID is the lower bound of menu IDs that will be processed. */ - -static void -dispose_menus (kind, id) - enum mac_menu_kind kind; - int id; -{ - for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++) - { - MenuRef menu = GetMenuRef (id); - - if (menu == NULL) - break; - DeleteMenu (id); - DisposeMenu (menu); - } -} - #endif /* HAVE_MENUS */ /* Detect if a menu is currently active. */ From 5d6c5138509b0bba003bf93d0b6fe9bcc77195af Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:58:39 +0000 Subject: [PATCH 10/56] [!TARGET_API_MAC_CARBON]: Don't include Scrap.h. (Selection): Move typedef to macgui.h. (Vselection_converter_alist, Qmac_scrap_name, Qmac_ostype) (Vmac_apple_event_map, Qmac_apple_event_class, Qmac_apple_event_id): Make variables non-static. (Vmac_dnd_known_types) [TARGET_API_MAC_CARBON]: Likewise. (mac_handle_apple_event, cleanup_all_suspended_apple_events): Make functions non-static. (Vmac_service_selection) [MAC_OSX]: Likewise. (mac_get_selection_from_symbol, get_flavor_type_from_symbol) (mac_valid_selection_target_p, mac_clear_selection) (mac_get_selection_ownership_info, mac_valid_selection_value_p) (mac_put_selection_value, mac_selection_has_target_p) (mac_get_selection_value, mac_get_selection_target_list) (init_apple_event_handler, install_drag_handler, remove_drag_handler): Move functions to mactoolbox.c. (mac_do_track_drag, mac_do_receive_drag) [TARGET_API_MAC_CARBON]: Likewise. (copy_scrap_flavor_data, mac_handle_service_event) (install_service_handler) [MAC_OSX]: Likewise. (syms_of_macselect) : Use mac_dnd_default_known_types. --- src/macselect.c | 768 +----------------------------------------------- 1 file changed, 12 insertions(+), 756 deletions(-) diff --git a/src/macselect.c b/src/macselect.c index 56efd496945..df7e98c0d67 100644 --- a/src/macselect.c +++ b/src/macselect.c @@ -25,38 +25,15 @@ Boston, MA 02110-1301, USA. */ #include "blockinput.h" #include "keymap.h" -#if TARGET_API_MAC_CARBON -typedef ScrapRef Selection; -#else /* !TARGET_API_MAC_CARBON */ -#include +#if !TARGET_API_MAC_CARBON #include -typedef int Selection; -#endif /* !TARGET_API_MAC_CARBON */ +#endif -static OSStatus mac_get_selection_from_symbol P_ ((Lisp_Object, int, - Selection *)); -static ScrapFlavorType get_flavor_type_from_symbol P_ ((Lisp_Object, - Selection)); -static int mac_valid_selection_target_p P_ ((Lisp_Object)); -static OSStatus mac_clear_selection P_ ((Selection *)); -static Lisp_Object mac_get_selection_ownership_info P_ ((Selection)); -static int mac_valid_selection_value_p P_ ((Lisp_Object, Lisp_Object)); -static OSStatus mac_put_selection_value P_ ((Selection, Lisp_Object, - Lisp_Object)); -static int mac_selection_has_target_p P_ ((Selection, Lisp_Object)); -static Lisp_Object mac_get_selection_value P_ ((Selection, Lisp_Object)); -static Lisp_Object mac_get_selection_target_list P_ ((Selection)); static void x_own_selection P_ ((Lisp_Object, Lisp_Object)); static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int)); static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object, Lisp_Object, Lisp_Object)); -EXFUN (Fx_selection_owner_p, 1); -#ifdef MAC_OSX -static OSStatus mac_handle_service_event P_ ((EventHandlerCallRef, - EventRef, void *)); -void init_service_handler P_ ((void)); -#endif Lisp_Object QPRIMARY, QSECONDARY, QTIMESTAMP, QTARGETS; @@ -98,302 +75,13 @@ static Lisp_Object Vselection_alist; selection value to a string representing the given selection type. This is for Lisp-level extension of the emacs selection handling. */ -static Lisp_Object Vselection_converter_alist; +Lisp_Object Vselection_converter_alist; /* A selection name (represented as a Lisp symbol) can be associated with a named scrap via `mac-scrap-name' property. Likewise for a selection type with a scrap flavor type via `mac-ostype'. */ -static Lisp_Object Qmac_scrap_name, Qmac_ostype; +Lisp_Object Qmac_scrap_name, Qmac_ostype; -#ifdef MAC_OSX -/* Selection name for communication via Services menu. */ -static Lisp_Object Vmac_service_selection; -#endif - -/* Get a reference to the selection corresponding to the symbol SYM. - The reference is set to *SEL, and it becomes NULL if there's no - corresponding selection. Clear the selection if CLEAR_P is - non-zero. */ - -static OSStatus -mac_get_selection_from_symbol (sym, clear_p, sel) - Lisp_Object sym; - int clear_p; - Selection *sel; -{ - OSStatus err = noErr; - Lisp_Object str = Fget (sym, Qmac_scrap_name); - - if (!STRINGP (str)) - *sel = NULL; - else - { -#if TARGET_API_MAC_CARBON -#ifdef MAC_OSX - CFStringRef scrap_name = cfstring_create_with_string (str); - OptionBits options = (clear_p ? kScrapClearNamedScrap - : kScrapGetNamedScrap); - - err = GetScrapByName (scrap_name, options, sel); - CFRelease (scrap_name); -#else /* !MAC_OSX */ - if (clear_p) - err = ClearCurrentScrap (); - if (err == noErr) - err = GetCurrentScrap (sel); -#endif /* !MAC_OSX */ -#else /* !TARGET_API_MAC_CARBON */ - if (clear_p) - err = ZeroScrap (); - if (err == noErr) - *sel = 1; -#endif /* !TARGET_API_MAC_CARBON */ - } - - return err; -} - -/* Get a scrap flavor type from the symbol SYM. Return 0 if no - corresponding flavor type. If SEL is non-zero, the return value is - non-zero only when the SEL has the flavor type. */ - -static ScrapFlavorType -get_flavor_type_from_symbol (sym, sel) - Lisp_Object sym; - Selection sel; -{ - Lisp_Object str = Fget (sym, Qmac_ostype); - ScrapFlavorType flavor_type; - - if (STRINGP (str) && SBYTES (str) == 4) - flavor_type = EndianU32_BtoN (*((UInt32 *) SDATA (str))); - else - flavor_type = 0; - - if (flavor_type && sel) - { -#if TARGET_API_MAC_CARBON - OSStatus err; - ScrapFlavorFlags flags; - - err = GetScrapFlavorFlags (sel, flavor_type, &flags); - if (err != noErr) - flavor_type = 0; -#else /* !TARGET_API_MAC_CARBON */ - SInt32 size, offset; - - size = GetScrap (NULL, flavor_type, &offset); - if (size < 0) - flavor_type = 0; -#endif /* !TARGET_API_MAC_CARBON */ - } - - return flavor_type; -} - -/* Check if the symbol SYM has a corresponding selection target type. */ - -static int -mac_valid_selection_target_p (sym) - Lisp_Object sym; -{ - return get_flavor_type_from_symbol (sym, 0) != 0; -} - -/* Clear the selection whose reference is *SEL. */ - -static OSStatus -mac_clear_selection (sel) - Selection *sel; -{ -#if TARGET_API_MAC_CARBON -#ifdef MAC_OSX - return ClearScrap (sel); -#else - OSStatus err; - - err = ClearCurrentScrap (); - if (err == noErr) - err = GetCurrentScrap (sel); - return err; -#endif -#else /* !TARGET_API_MAC_CARBON */ - return ZeroScrap (); -#endif /* !TARGET_API_MAC_CARBON */ -} - -/* Get ownership information for SEL. Emacs can detect a change of - the ownership by comparing saved and current values of the - ownership information. */ - -static Lisp_Object -mac_get_selection_ownership_info (sel) - Selection sel; -{ -#if TARGET_API_MAC_CARBON - return long_to_cons ((unsigned long) sel); -#else /* !TARGET_API_MAC_CARBON */ - ScrapStuffPtr scrap_info = InfoScrap (); - - return make_number (scrap_info->scrapCount); -#endif /* !TARGET_API_MAC_CARBON */ -} - -/* Return non-zero if VALUE is a valid selection value for TARGET. */ - -static int -mac_valid_selection_value_p (value, target) - Lisp_Object value, target; -{ - return STRINGP (value); -} - -/* Put Lisp Object VALUE to the selection SEL. The target type is - specified by TARGET. */ - -static OSStatus -mac_put_selection_value (sel, target, value) - Selection sel; - Lisp_Object target, value; -{ - ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, 0); - - if (flavor_type == 0 || !STRINGP (value)) - return noTypeErr; - -#if TARGET_API_MAC_CARBON - return PutScrapFlavor (sel, flavor_type, kScrapFlavorMaskNone, - SBYTES (value), SDATA (value)); -#else /* !TARGET_API_MAC_CARBON */ - return PutScrap (SBYTES (value), flavor_type, SDATA (value)); -#endif /* !TARGET_API_MAC_CARBON */ -} - -/* Check if data for the target type TARGET is available in SEL. */ - -static int -mac_selection_has_target_p (sel, target) - Selection sel; - Lisp_Object target; -{ - return get_flavor_type_from_symbol (target, sel) != 0; -} - -/* Get data for the target type TARGET from SEL and create a Lisp - string. Return nil if failed to get data. */ - -static Lisp_Object -mac_get_selection_value (sel, target) - Selection sel; - Lisp_Object target; -{ - OSStatus err; - Lisp_Object result = Qnil; - ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, sel); -#if TARGET_API_MAC_CARBON - Size size; - - if (flavor_type) - { - err = GetScrapFlavorSize (sel, flavor_type, &size); - if (err == noErr) - { - do - { - result = make_uninit_string (size); - err = GetScrapFlavorData (sel, flavor_type, - &size, SDATA (result)); - if (err != noErr) - result = Qnil; - else if (size < SBYTES (result)) - result = make_unibyte_string (SDATA (result), size); - } - while (STRINGP (result) && size > SBYTES (result)); - } - } -#else - Handle handle; - SInt32 size, offset; - - if (flavor_type) - size = GetScrap (NULL, flavor_type, &offset); - if (size >= 0) - { - handle = NewHandle (size); - HLock (handle); - size = GetScrap (handle, flavor_type, &offset); - if (size >= 0) - result = make_unibyte_string (*handle, size); - DisposeHandle (handle); - } -#endif - - return result; -} - -/* Get the list of target types in SEL. The return value is a list of - target type symbols possibly followed by scrap flavor type - strings. */ - -static Lisp_Object -mac_get_selection_target_list (sel) - Selection sel; -{ - Lisp_Object result = Qnil, rest, target; -#if TARGET_API_MAC_CARBON - OSStatus err; - UInt32 count, i, type; - ScrapFlavorInfo *flavor_info = NULL; - Lisp_Object strings = Qnil; - - err = GetScrapFlavorCount (sel, &count); - if (err == noErr) - flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count); - err = GetScrapFlavorInfoList (sel, &count, flavor_info); - if (err != noErr) - { - xfree (flavor_info); - flavor_info = NULL; - } - if (flavor_info == NULL) - count = 0; -#endif - for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest)) - { - ScrapFlavorType flavor_type = 0; - - if (CONSP (XCAR (rest)) - && (target = XCAR (XCAR (rest)), - SYMBOLP (target)) - && (flavor_type = get_flavor_type_from_symbol (target, sel))) - { - result = Fcons (target, result); -#if TARGET_API_MAC_CARBON - for (i = 0; i < count; i++) - if (flavor_info[i].flavorType == flavor_type) - { - flavor_info[i].flavorType = 0; - break; - } -#endif - } - } -#if TARGET_API_MAC_CARBON - if (flavor_info) - { - for (i = 0; i < count; i++) - if (flavor_info[i].flavorType) - { - type = EndianU32_NtoB (flavor_info[i].flavorType); - strings = Fcons (make_unibyte_string ((char *) &type, 4), strings); - } - result = nconc2 (result, strings); - xfree (flavor_info); - } -#endif - - return result; -} /* Do protocol to assert ourself as a selection owner. Update the Vselection_alist so that we can reply to later requests for @@ -892,8 +580,8 @@ and t is the same as `SECONDARY'. */) Apple event support ***********************************************************************/ int mac_ready_for_apple_events = 0; -static Lisp_Object Vmac_apple_event_map; -static Lisp_Object Qmac_apple_event_class, Qmac_apple_event_id; +Lisp_Object Vmac_apple_event_map; +Lisp_Object Qmac_apple_event_class, Qmac_apple_event_id; static Lisp_Object Qemacs_suspension_id; extern Lisp_Object Qundefined; extern void mac_store_apple_event P_ ((Lisp_Object, Lisp_Object, @@ -1095,7 +783,7 @@ mac_handle_apple_event_1 (class, id, apple_event, reply) return err; } -static pascal OSErr +pascal OSErr mac_handle_apple_event (apple_event, reply, refcon) const AppleEvent *apple_event; AppleEvent *reply; @@ -1173,40 +861,13 @@ cleanup_suspended_apple_events (head, all_p) return nresumed; } -static void +void cleanup_all_suspended_apple_events () { cleanup_suspended_apple_events (&deferred_apple_events, 1); cleanup_suspended_apple_events (&suspended_apple_events, 1); } -void -init_apple_event_handler () -{ - OSErr err; - long result; - - /* Make sure we have Apple events before starting. */ - err = Gestalt (gestaltAppleEventsAttr, &result); - if (err != noErr) - abort (); - - if (!(result & (1 << gestaltAppleEventsPresent))) - abort (); - - err = AEInstallEventHandler (typeWildCard, typeWildCard, -#if TARGET_API_MAC_CARBON - NewAEEventHandlerUPP (mac_handle_apple_event), -#else - NewAEEventHandlerProc (mac_handle_apple_event), -#endif - 0L, false); - if (err != noErr) - abort (); - - atexit (cleanup_all_suspended_apple_events); -} - static UInt32 get_suspension_id (apple_event) Lisp_Object apple_event; @@ -1399,419 +1060,18 @@ nil, which means the event is already resumed or expired. */) Drag and drop support ***********************************************************************/ #if TARGET_API_MAC_CARBON -static Lisp_Object Vmac_dnd_known_types; -static pascal OSErr mac_do_track_drag P_ ((DragTrackingMessage, WindowRef, - void *, DragRef)); -static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef)); -static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL; -static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL; - -extern void mac_store_drag_event P_ ((WindowRef, Point, SInt16, - const AEDesc *)); - -static pascal OSErr -mac_do_track_drag (message, window, refcon, drag) - DragTrackingMessage message; - WindowRef window; - void *refcon; - DragRef drag; -{ - OSErr err = noErr; - static int can_accept; - UInt16 num_items, index; - - if (GetFrontWindowOfClass (kMovableModalWindowClass, false)) - return dragNotAcceptedErr; - - switch (message) - { - case kDragTrackingEnterHandler: - err = CountDragItems (drag, &num_items); - if (err != noErr) - break; - can_accept = 0; - for (index = 1; index <= num_items; index++) - { - ItemReference item; - FlavorFlags flags; - Lisp_Object rest; - - err = GetDragItemReferenceNumber (drag, index, &item); - if (err != noErr) - continue; - for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest)) - { - Lisp_Object str; - FlavorType type; - - str = XCAR (rest); - if (!(STRINGP (str) && SBYTES (str) == 4)) - continue; - type = EndianU32_BtoN (*((UInt32 *) SDATA (str))); - - err = GetFlavorFlags (drag, item, type, &flags); - if (err == noErr) - { - can_accept = 1; - break; - } - } - } - break; - - case kDragTrackingEnterWindow: - if (can_accept) - { - RgnHandle hilite_rgn = NewRgn (); - - if (hilite_rgn) - { - Rect r; - - GetWindowPortBounds (window, &r); - OffsetRect (&r, -r.left, -r.top); - RectRgn (hilite_rgn, &r); - ShowDragHilite (drag, hilite_rgn, true); - DisposeRgn (hilite_rgn); - } - SetThemeCursor (kThemeCopyArrowCursor); - } - break; - - case kDragTrackingInWindow: - break; - - case kDragTrackingLeaveWindow: - if (can_accept) - { - HideDragHilite (drag); - SetThemeCursor (kThemeArrowCursor); - } - break; - - case kDragTrackingLeaveHandler: - break; - } - - if (err != noErr) - return dragNotAcceptedErr; - return noErr; -} - -static pascal OSErr -mac_do_receive_drag (window, refcon, drag) - WindowRef window; - void *refcon; - DragRef drag; -{ - OSErr err; - int num_types, i; - Lisp_Object rest, str; - FlavorType *types; - AppleEvent apple_event; - Point mouse_pos; - SInt16 modifiers; - - if (GetFrontWindowOfClass (kMovableModalWindowClass, false)) - return dragNotAcceptedErr; - - num_types = 0; - for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest)) - { - str = XCAR (rest); - if (STRINGP (str) && SBYTES (str) == 4) - num_types++; - } - - types = xmalloc (sizeof (FlavorType) * num_types); - i = 0; - for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest)) - { - str = XCAR (rest); - if (STRINGP (str) && SBYTES (str) == 4) - types[i++] = EndianU32_BtoN (*((UInt32 *) SDATA (str))); - } - - err = create_apple_event_from_drag_ref (drag, num_types, types, - &apple_event); - xfree (types); - - if (err == noErr) - err = GetDragMouse (drag, &mouse_pos, NULL); - if (err == noErr) - { - GlobalToLocal (&mouse_pos); - err = GetDragModifiers (drag, NULL, NULL, &modifiers); - } - if (err == noErr) - { - UInt32 key_modifiers = modifiers; - - err = AEPutParamPtr (&apple_event, kEventParamKeyModifiers, - typeUInt32, &key_modifiers, sizeof (UInt32)); - } - - if (err == noErr) - { - mac_store_drag_event (window, mouse_pos, 0, &apple_event); - AEDisposeDesc (&apple_event); - mac_wakeup_from_rne (); - return noErr; - } - else - return dragNotAcceptedErr; -} +Lisp_Object Vmac_dnd_known_types; #endif /* TARGET_API_MAC_CARBON */ -OSErr -install_drag_handler (window) - WindowRef window; -{ - OSErr err = noErr; - -#if TARGET_API_MAC_CARBON - if (mac_do_track_dragUPP == NULL) - mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag); - if (mac_do_receive_dragUPP == NULL) - mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag); - - err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL); - if (err == noErr) - err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL); -#endif - - return err; -} - -void -remove_drag_handler (window) - WindowRef window; -{ -#if TARGET_API_MAC_CARBON - if (mac_do_track_dragUPP) - RemoveTrackingHandler (mac_do_track_dragUPP, window); - if (mac_do_receive_dragUPP) - RemoveReceiveHandler (mac_do_receive_dragUPP, window); -#endif -} - /*********************************************************************** Services menu support ***********************************************************************/ #ifdef MAC_OSX -OSStatus -install_service_handler () -{ - static const EventTypeSpec specs[] = - {{kEventClassService, kEventServiceGetTypes}, - {kEventClassService, kEventServiceCopy}, - {kEventClassService, kEventServicePaste}, - {kEventClassService, kEventServicePerform}}; - - return InstallApplicationEventHandler (NewEventHandlerUPP - (mac_handle_service_event), - GetEventTypeCount (specs), - specs, NULL, NULL); -} - -extern OSStatus mac_store_service_event P_ ((EventRef)); - -static OSStatus -copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type) - ScrapRef from_scrap, to_scrap; - ScrapFlavorType flavor_type; -{ - OSStatus err; - Size size, size_allocated; - char *buf = NULL; - - err = GetScrapFlavorSize (from_scrap, flavor_type, &size); - if (err == noErr) - buf = xmalloc (size); - while (buf) - { - size_allocated = size; - err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf); - if (err != noErr) - { - xfree (buf); - buf = NULL; - } - else if (size_allocated < size) - buf = xrealloc (buf, size); - else - break; - } - if (err == noErr) - { - if (buf == NULL) - err = memFullErr; - else - { - err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone, - size, buf); - xfree (buf); - } - } - - return err; -} - -static OSStatus -mac_handle_service_event (call_ref, event, data) - EventHandlerCallRef call_ref; - EventRef event; - void *data; -{ - OSStatus err = noErr; - ScrapRef cur_scrap, specific_scrap; - UInt32 event_kind = GetEventKind (event); - CFMutableArrayRef copy_types, paste_types; - CFStringRef type; - Lisp_Object rest; - ScrapFlavorType flavor_type; - - /* Check if Vmac_service_selection is a valid selection that has a - corresponding scrap. */ - if (!SYMBOLP (Vmac_service_selection)) - err = eventNotHandledErr; - else - err = mac_get_selection_from_symbol (Vmac_service_selection, 0, &cur_scrap); - if (!(err == noErr && cur_scrap)) - return eventNotHandledErr; - - switch (event_kind) - { - case kEventServiceGetTypes: - /* Set paste types. */ - err = GetEventParameter (event, kEventParamServicePasteTypes, - typeCFMutableArrayRef, NULL, - sizeof (CFMutableArrayRef), NULL, - &paste_types); - if (err != noErr) - break; - - for (rest = Vselection_converter_alist; CONSP (rest); - rest = XCDR (rest)) - if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest))) - && (flavor_type = - get_flavor_type_from_symbol (XCAR (XCAR (rest)), 0))) - { - type = CreateTypeStringWithOSType (flavor_type); - if (type) - { - CFArrayAppendValue (paste_types, type); - CFRelease (type); - } - } - - /* Set copy types. */ - err = GetEventParameter (event, kEventParamServiceCopyTypes, - typeCFMutableArrayRef, NULL, - sizeof (CFMutableArrayRef), NULL, - ©_types); - if (err != noErr) - break; - - if (NILP (Fx_selection_owner_p (Vmac_service_selection))) - break; - else - goto copy_all_flavors; - - case kEventServiceCopy: - err = GetEventParameter (event, kEventParamScrapRef, - typeScrapRef, NULL, - sizeof (ScrapRef), NULL, &specific_scrap); - if (err != noErr - || NILP (Fx_selection_owner_p (Vmac_service_selection))) - { - err = eventNotHandledErr; - break; - } - - copy_all_flavors: - { - UInt32 count, i; - ScrapFlavorInfo *flavor_info = NULL; - ScrapFlavorFlags flags; - - err = GetScrapFlavorCount (cur_scrap, &count); - if (err == noErr) - flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count); - err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info); - if (err != noErr) - { - xfree (flavor_info); - flavor_info = NULL; - } - if (flavor_info == NULL) - break; - - for (i = 0; i < count; i++) - { - flavor_type = flavor_info[i].flavorType; - err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags); - if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly)) - { - if (event_kind == kEventServiceCopy) - err = copy_scrap_flavor_data (cur_scrap, specific_scrap, - flavor_type); - else /* event_kind == kEventServiceGetTypes */ - { - type = CreateTypeStringWithOSType (flavor_type); - if (type) - { - CFArrayAppendValue (copy_types, type); - CFRelease (type); - } - } - } - } - xfree (flavor_info); - } - break; - - case kEventServicePaste: - case kEventServicePerform: - { - int data_exists_p = 0; - - err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef, - NULL, sizeof (ScrapRef), NULL, - &specific_scrap); - if (err == noErr) - err = mac_clear_selection (&cur_scrap); - if (err == noErr) - for (rest = Vselection_converter_alist; CONSP (rest); - rest = XCDR (rest)) - { - if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest))))) - continue; - flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)), - specific_scrap); - if (flavor_type == 0) - continue; - err = copy_scrap_flavor_data (specific_scrap, cur_scrap, - flavor_type); - if (err == noErr) - data_exists_p = 1; - } - if (!data_exists_p) - err = eventNotHandledErr; - else - err = mac_store_service_event (event); - } - break; - } - - if (err != noErr) - err = eventNotHandledErr; - return err; -} +/* Selection name for communication via Services menu. */ +Lisp_Object Vmac_service_selection; #endif - void syms_of_macselect () { @@ -1870,11 +1130,7 @@ set to nil. */); DEFVAR_LISP ("mac-dnd-known-types", &Vmac_dnd_known_types, doc: /* The types accepted by default for dropped data. The types are chosen in the order they appear in the list. */); - Vmac_dnd_known_types = list4 (build_string ("hfs "), build_string ("utxt"), - build_string ("TEXT"), build_string ("TIFF")); -#ifdef MAC_OSX - Vmac_dnd_known_types = Fcons (build_string ("furl"), Vmac_dnd_known_types); -#endif + Vmac_dnd_known_types = mac_dnd_default_known_types (); #endif #ifdef MAC_OSX From f2ec385ecd26c73ea9014ddfa009999b4cc2b24b Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:58:59 +0000 Subject: [PATCH 11/56] (mac_end_cg_clip): Add argument F. All uses changed. (mac_begin_cg_clip, mac_end_cg_clip): Allow null GC. (mac_invert_rectangle, mac_compute_glyph_string_overhangs) (mac_load_query_font): Use them instead of SetPortWindowPort. (mac_clear_window) [!USE_CG_DRAWING]: Likewise. (mac_draw_image_string_cg): Call CGContextSetTextMatrix. (x_update_begin, x_update_end): Call mac_update_begin and mac_update_end. (XTframe_up_to_date): Call mac_frame_up_to_date. (XTring_bell): Use mac_alert_sound_play. (note_mouse_movement): Use mac_get_frame_bounds. (XTmouse_position): Use mac_get_frame_mouse. (x_scroll_bar_create): Use mac_create_scroll_bar. (x_scroll_bar_remove): Use mac_dispose_scroll_bar. (XTset_vertical_scroll_bar): Use mac_set_scroll_bar_bounds and mac_redraw_scroll_bar. (mac_move_window_with_gravity) [USE_MAC_TOOLBAR]: Use mac_move_window instead of MoveWindow. (mac_handle_size_change) [TARGET_API_MAC_CARBON]: Use mac_reposition_hourglass. (x_set_offset): Use mac_move_window_structure instead of MoveWindowStructure. (x_set_window_size): Use mac_size_window instead of SizeWindow. (x_set_mouse_pixel_position) [MAC_OSX]: Use mac_convert_frame_point_to_global. (x_raise_frame): Use mac_bring_window_to_front instead of BringToFront. (x_lower_frame): Use mac_send_window_behind instead of SendBehind. (mac_handle_visibility_change): Use Window instead of WindowRef. Use mac_is_window_visible/mac_is_window_collapsed instead of IsWindowVisible/IsWindowCollapsed, respectively. Use mac_collapse_window/mac_show_window instead of CollapseWindow/ShowWindow, respectively. (x_make_frame_invisible): Use mac_hide_window instead of HideWindow. (x_iconify_frame): Use mac_show_window instead of ShowWindow. Use mac_collapse_window instead of CollapseWindow. (x_free_frame_resources): Use Window instead of WindowRef. Use mac_dispose_frame_window. Clean up focus-related variables before calling mac_dispose_frame_window. (do_zoom_window) [MAC_OS8]: Use mac_clear_area instead of mac_clear_window. (mac_initialize): Use mac_toolbox_initialize instead of initializing any_help_event_p and calling init_apple_event_handler, init_tsm, and init_menu_bar. (any_help_event_p, last_window, save_port_clip_region) (read_socket_inev, saved_menu_event_location): Move variables to mactoolbox.c. (last_scroll_bar_part, scroll_bar_timer) (scroll_bar_timer_event_posted_p) [USE_TOOLKIT_SCROLL_BARS]: Likewise. (font_panel_shown_p) [USE_MAC_FONT_PANEL]: Likewise. (tsm_document_id) [USE_MAC_TSM]: Likewise. (mouse_region) [!TARGET_API_MAC_CARBON]: Likewise. (mac_window_to_frame, DEFAULT_NUM_COLS, MIN_DOC_SIZE, MAX_DOC_SIZE): Move defines to mactoolbox.c. (FRAME_CG_CONTEXT) [USE_CG_DRAWING]: Likewise. (SCROLL_BAR_FIRST_DELAY, SCROLL_BAR_CONTINUOUS_DELAY) [USE_TOOLKIT_SCROLL_BARS]: Likewise. (TOOLBAR_IDENTIFIER, TOOLBAR_ICON_ITEM_IDENTIFIER) (TOOLBAR_ITEM_COMMAND_ID_OFFSET, TOOLBAR_ITEM_COMMAND_ID_P) (TOOLBAR_ITEM_COMMAND_ID_VALUE, TOOLBAR_ITEM_MAKE_COMMAND_ID) [USE_MAC_TOOLBAR]: Likewise. (M_APPLE, I_ABOUT, EXTRA_STACK_ALLOC, ARGV_STRING_LIST_ID) (RAM_TOO_LARGE_ALERT_ID, ABOUT_ALERT_ID): Move defines to macgui.h (x_flush, is_emacs_window, mac_begin_clip, mac_end_clip) (x_scroll_bar_handle_click, x_scroll_bar_report_motion) (mac_get_window_bounds, do_window_update, is_emacs_window) (do_grow_window, do_zoom_window, install_window_handler) (remove_window_handler, XTread_socket, init_menu_bar): Move functions to mactoolbox.c. (mac_flush_display_optional, mac_begin_cg_clip, mac_end_cg_clip) (mac_prepare_for_quickdraw) [USE_CG_DRAWING]: Likewise. (mac_scroll_area, mac_event_to_emacs_modifiers, mac_get_mouse_btn) (mac_convert_event_ref, mac_get_ideal_size, mac_store_drag_event) (mac_handle_window_event, mac_handle_keyboard_event) (mac_handle_command_event, mac_handle_mouse_event) (install_application_handler, mac_post_mouse_moved_event) [TARGET_API_MAC_CARBON]: Likewise. (scroll_bar_timer_callback, install_scroll_bar_timer) (set_scroll_bar_timer, control_part_code_to_scroll_bar_part) (construct_scroll_bar_click, get_control_part_bounds) (x_scroll_bar_handle_press, x_scroll_bar_handle_release) (x_scroll_bar_handle_drag, x_set_toolkit_scroll_bar_thumb) [USE_TOOLKIT_SCROLL_BARS]: Likewise. (x_scroll_bar_set_handle, x_scroll_bar_note_movement) [!USE_TOOLKIT_SCROLL_BARS]: Likewise. (mac_handle_toolbar_event, mac_create_frame_tool_bar) (update_frame_tool_bar, free_frame_tool_bar) (mac_tool_bar_note_mouse_movement, mac_handle_toolbar_command_event) [USE_MAC_TOOLBAR]: Likewise. (mac_font_panel_visible_p, mac_handle_font_event) (mac_show_hide_font_panel, mac_set_font_info_for_selection) [USE_MAC_FONT_PANEL]: Likewise. (mac_handle_text_input_event, init_tsm) [USE_MAC_TSM]: Likewise. (do_apple_menu, mac_wait_next_event) [!TARGET_API_MAC_CARBON]: Likewise. (mac_store_service_event) [MAC_OSX]: Likewise. (last_mouse_glyph, last_mouse_glyph_frame, last_mouse_scroll_bar) (last_mouse_movement_time, input_signal_count) (mac_screen_config_changed, Qhi_command, Qtoolbar_switch_mode) (Qservice, Qpaste, Qperform, keycode_to_xkeysym_table): Make variables non-static. (Qpanel_closed, Qselection) [USE_MAC_FONT_PANEL]: Likewise. (Qtext_input, Vmac_ts_active_input_overlay, Qupdate_active_input_area) (Qunicode_for_key_event, Vmac_ts_script_language_on_focus) (saved_ts_script_language_on_focus) [USE_MAC_TSM]: Likewise. (mac_focus_changed, note_mouse_movement, mac_focus_frame) (mac_handle_origin_change, mac_handle_size_change) (mac_handle_visibility_change, mac_to_emacs_modifiers) (mac_mapped_modifiers, mac_get_emulated_btn, do_keystroke) (mac_get_screen_info): Make functions non-static. (mac_move_window_with_gravity, mac_get_window_origin_with_gravity) (mac_image_spec_to_cg_image) [USE_MAC_TOOLBAR]: Likewise. (mac_store_event_ref_as_apple_event) [TARGET_API_MAC_CARBON]: Likewise. (Qwindow, mac_ready_for_apple_events): Move externs to mactoolbox.c. (Qbefore_string) [USE_MAC_TSM]: Likewise. (mac_toolbox_initialize, x_scroll_bar_report_motion, XTread_socket): Add externs. (mac_flush_display_optional) [USE_CG_DRAWING]: Likewise. (install_drag_handler, remove_drag_handler, install_service_handler) (install_menu_target_item_handler): Remove externs. (XSetWindowBackground): Rename to mac_set_frame_window_background. Take frame as argument instead of display and window. Move to mactoolbox.c. (mac_restore_keyboard_input_source, mac_save_keyboard_input_source) [USE_MAC_TSM]: New functions created from mac_tsm_resume and mac_tsm_suspend, respectively. (mac_tsm_resume, mac_tsm_suspend) [USE_MAC_TSM]: Use them. Move to mactoolbox.c. --- src/macterm.c | 4098 ++++--------------------------------------------- 1 file changed, 291 insertions(+), 3807 deletions(-) diff --git a/src/macterm.c b/src/macterm.c index 9e5753ec3cc..a043e5a4860 100644 --- a/src/macterm.c +++ b/src/macterm.c @@ -91,15 +91,6 @@ Lisp_Object Vx_toolkit_scroll_bars; rendering which may anti-alias the text. */ int mac_use_core_graphics; - -/* Non-zero means that a HELP_EVENT has been generated since Emacs - start. */ - -static int any_help_event_p; - -/* Last window where we saw the mouse. Used by mouse-autoselect-window. */ -static Lisp_Object last_window; - /* Non-zero means make use of UNDERLINE_POSITION font properties. (Not yet supported.) */ int x_use_underline_position_properties; @@ -159,8 +150,8 @@ struct frame *pending_autoraise_frame; /* Where the mouse was last time we reported a mouse event. */ -static Rect last_mouse_glyph; -static FRAME_PTR last_mouse_glyph_frame; +Rect last_mouse_glyph; +FRAME_PTR last_mouse_glyph_frame; /* The scroll bar in which the last X motion event occurred. @@ -172,7 +163,7 @@ static FRAME_PTR last_mouse_glyph_frame; this to Qnil, to tell XTmouse_position to return an ordinary motion event. */ -static Lisp_Object last_mouse_scroll_bar; +Lisp_Object last_mouse_scroll_bar; /* This is a hack. We would really prefer that XTmouse_position would return the time associated with the position it returns, but there @@ -181,7 +172,7 @@ static Lisp_Object last_mouse_scroll_bar; of the last movement we received, and return that in hopes that it's somewhat accurate. */ -static Time last_mouse_movement_time; +Time last_mouse_movement_time; struct scroll_bar *tracked_scroll_bar = NULL; @@ -189,9 +180,9 @@ struct scroll_bar *tracked_scroll_bar = NULL; events. */ #ifdef __STDC__ -static int volatile input_signal_count; +int volatile input_signal_count; #else -static int input_signal_count; +int input_signal_count; #endif extern Lisp_Object Vsystem_name; @@ -212,8 +203,6 @@ extern int inhibit_window_system; QDGlobals qd; /* QuickDraw global information structure. */ #endif -#define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP) - struct mac_display_info *mac_display_info_for_display (Display *); static void x_update_window_end P_ ((struct window *, int, int)); int x_catch_errors P_ ((Display *)); @@ -237,11 +226,6 @@ static void x_clear_frame P_ ((void)); static void frame_highlight P_ ((struct frame *)); static void frame_unhighlight P_ ((struct frame *)); static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *)); -static void mac_focus_changed P_ ((int, struct mac_display_info *, - struct frame *, struct input_event *)); -static void x_detect_focus_change P_ ((struct mac_display_info *, - const EventRecord *, - struct input_event *)); static void XTframe_rehighlight P_ ((struct frame *)); static void x_frame_rehighlight P_ ((struct x_display_info *)); static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *)); @@ -249,18 +233,21 @@ static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int, enum text_cursor_kinds)); static void x_clip_to_row P_ ((struct window *, struct glyph_row *, int, GC)); -static void x_flush P_ ((struct frame *f)); static void x_update_begin P_ ((struct frame *)); static void x_update_window_begin P_ ((struct window *)); static void x_after_update_window_line P_ ((struct glyph_row *)); -static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *, + +static XCharStruct *mac_per_char_metric P_ ((XFontStruct *, XChar2b *, int)); +static void XSetFont P_ ((Display *, GC, XFontStruct *)); + +extern void mac_toolbox_initialize P_ ((void)); +extern void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *, enum scroll_bar_part *, Lisp_Object *, Lisp_Object *, unsigned long *)); - -static int is_emacs_window P_ ((WindowRef)); -static XCharStruct *mac_per_char_metric P_ ((XFontStruct *, XChar2b *, int)); -static void XSetFont P_ ((Display *, GC, XFontStruct *)); +#if USE_CG_DRAWING +extern void mac_flush_display_optional P_ ((struct frame *)); +#endif #define GC_FORE_COLOR(gc) (&(gc)->fore_color) #define GC_BACK_COLOR(gc) (&(gc)->back_color) @@ -324,8 +311,6 @@ static void XSetFont P_ ((Display *, GC, XFontStruct *)); (gc)->cg_fore_color) #if USE_CG_DRAWING -#define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context) - /* Fringe bitmaps. */ static int max_fringe_bmp = 0; @@ -353,96 +338,7 @@ init_cg_color () } #endif } - -static CGContextRef -mac_begin_cg_clip (f, gc) - struct frame *f; - GC gc; -{ - CGContextRef context = FRAME_CG_CONTEXT (f); - - if (!context) - { - QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context); - FRAME_CG_CONTEXT (f) = context; - } - - CGContextSaveGState (context); - CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f)); - CGContextScaleCTM (context, 1, -1); - if (gc && gc->n_clip_rects) - CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects); - - return context; -} - -static void -mac_end_cg_clip (f) - struct frame *f; -{ - CGContextRestoreGState (FRAME_CG_CONTEXT (f)); -} - -void -mac_prepare_for_quickdraw (f) - struct frame *f; -{ - if (f == NULL) - { - Lisp_Object rest, frame; - FOR_EACH_FRAME (rest, frame) - if (FRAME_MAC_P (XFRAME (frame))) - mac_prepare_for_quickdraw (XFRAME (frame)); - } - else - { - CGContextRef context = FRAME_CG_CONTEXT (f); - - if (context) - { - CGContextSynchronize (context); - QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), - &FRAME_CG_CONTEXT (f)); - } - } -} -#endif - -static RgnHandle saved_port_clip_region = NULL; - -static void -mac_begin_clip (f, gc) - struct frame *f; - GC gc; -{ - static RgnHandle new_region = NULL; - - if (saved_port_clip_region == NULL) - saved_port_clip_region = NewRgn (); - if (new_region == NULL) - new_region = NewRgn (); - -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - SetPortWindowPort (FRAME_MAC_WINDOW (f)); - - if (gc->n_clip_rects) - { - GetClip (saved_port_clip_region); - SectRgn (saved_port_clip_region, gc->clip_region, new_region); - SetClip (new_region); - } -} - -static void -mac_end_clip (gc) - GC gc; -{ - if (gc->n_clip_rects) - SetClip (saved_port_clip_region); -} - +#endif /* USE_CG_DRAWING */ /* X display function emulation */ @@ -491,7 +387,7 @@ mac_draw_line (f, gc, x1, y1, x2, y2) RGBForeColor (GC_FORE_COLOR (gc)); MoveTo (x1, y1); LineTo (x2, y2); - mac_end_clip (gc); + mac_end_clip (f, gc); #endif } @@ -561,7 +457,7 @@ mac_erase_rectangle (f, gc, x, y, width, height) SetRect (&r, x, y, x + width, y + height); EraseRect (&r); RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f))); - mac_end_clip (gc); + mac_end_clip (f, gc); } #endif } @@ -596,10 +492,8 @@ mac_clear_window (f) mac_end_cg_clip (f); } #else /* !USE_CG_DRAWING */ - SetPortWindowPort (FRAME_MAC_WINDOW (f)); - + mac_begin_clip (f, NULL); RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f))); - #if TARGET_API_MAC_CARBON { Rect r; @@ -610,6 +504,7 @@ mac_clear_window (f) #else /* not TARGET_API_MAC_CARBON */ EraseRect (&(FRAME_MAC_WINDOW (f)->portRect)); #endif /* not TARGET_API_MAC_CARBON */ + mac_end_clip (f, NULL); #endif } @@ -688,7 +583,7 @@ mac_draw_bitmap (f, gc, x, y, width, height, bits, overlay_p) overlay_p ? srcOr : srcCopy, 0); #endif /* not TARGET_API_MAC_CARBON */ RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f))); - mac_end_clip (gc); + mac_end_clip (f, gc); } #endif /* !USE_CG_DRAWING */ @@ -843,7 +738,7 @@ mac_fill_rectangle (f, gc, x, y, width, height) RGBForeColor (GC_FORE_COLOR (gc)); SetRect (&r, x, y, x + width, y + height); PaintRect (&r); /* using foreground color of gc */ - mac_end_clip (gc); + mac_end_clip (f, gc); #endif } @@ -872,7 +767,7 @@ mac_draw_rectangle (f, gc, x, y, width, height) RGBForeColor (GC_FORE_COLOR (gc)); SetRect (&r, x, y, x + width + 1, y + height + 1); FrameRect (&r); /* using foreground color of gc */ - mac_end_clip (gc); + mac_end_clip (f, gc); #endif } @@ -885,14 +780,10 @@ mac_invert_rectangle (f, x, y, width, height) { Rect r; -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - SetPortWindowPort (FRAME_MAC_WINDOW (f)); - + mac_begin_clip (f, NULL); SetRect (&r, x, y, x + width, y + height); - InvertRect (&r); + mac_end_clip (f, NULL); } @@ -1008,7 +899,7 @@ mac_draw_image_string_atsui (f, gc, x, y, buf, nchars, bg_width, kATSUFromTextBeginning, kATSUToTextEnd, kATSUUseGrafPortPenLoc, kATSUUseGrafPortPenLoc); } - mac_end_clip (gc); + mac_end_clip (f, gc); #ifdef MAC_OSX } else @@ -1142,7 +1033,7 @@ mac_draw_image_string_qd (f, gc, x, y, buf, nchars, bg_width, } if (bg_width) RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f))); - mac_end_clip (gc); + mac_end_clip (f, gc); #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 if (mac_use_core_graphics) @@ -1437,6 +1328,7 @@ mac_draw_image_string_cg (f, gc, x, y, buf, nchars, bg_width, overstrike_p) CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, gc); CGContextSetFont (context, GC_FONT (gc)->cg_font); CGContextSetFontSize (context, GC_FONT (gc)->mac_fontsize); + CGContextSetTextMatrix (context, CGAffineTransformIdentity); if (GC_FONT (gc)->mac_fontsize <= cg_text_anti_aliasing_threshold) CGContextSetShouldAntialias (context, false); #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 @@ -1521,7 +1413,7 @@ mac_copy_area (src, f, gc, src_x, src_y, width, height, dest_x, dest_y) RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f))); - mac_end_clip (gc); + mac_end_clip (f, gc); } @@ -1567,13 +1459,18 @@ mac_copy_area_with_mask (src, mask, f, gc, src_x, src_y, RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f))); - mac_end_clip (gc); + mac_end_clip (f, gc); } #endif /* !USE_CG_DRAWING */ /* Mac replacement for XCopyArea: used only for scrolling. */ +#if TARGET_API_MAC_CARBON +/* Defined in mactoolbox.c. */ +extern void mac_scroll_area P_ ((struct frame *, GC, int, int, + unsigned int, unsigned int, int, int)); +#else /* not TARGET_API_MAC_CARBON */ static void mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y) struct frame *f; @@ -1582,19 +1479,6 @@ mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y) unsigned int width, height; int dest_x, dest_y; { -#if TARGET_API_MAC_CARBON - Rect src_r; - RgnHandle dummy = NewRgn (); /* For avoiding update events. */ - - SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - ScrollWindowRect (FRAME_MAC_WINDOW (f), - &src_r, dest_x - src_x, dest_y - src_y, - kScrollWindowNoOptions, dummy); - DisposeRgn (dummy); -#else /* not TARGET_API_MAC_CARBON */ Rect src_r, dest_r; WindowRef w = FRAME_MAC_WINDOW (f); @@ -1611,9 +1495,9 @@ mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y) RGBBackColor (GC_BACK_COLOR (FRAME_NORMAL_GC (f))); - mac_end_clip (gc); -#endif /* not TARGET_API_MAC_CARBON */ + mac_end_clip (f, gc); } +#endif /* not TARGET_API_MAC_CARBON */ /* Mac replacement for XChangeGC. */ @@ -1850,70 +1734,6 @@ mac_reset_clip_rectangles (display, gc) gc->n_clip_rects = 0; } - -/* Mac replacement for XSetWindowBackground. */ - -void -XSetWindowBackground (display, w, color) - Display *display; - WindowRef w; - unsigned long color; -{ -#if !TARGET_API_MAC_CARBON - AuxWinHandle aw_handle; - CTabHandle ctab_handle; - ColorSpecPtr ct_table; - short ct_size; -#endif - RGBColor bg_color; - - bg_color.red = RED16_FROM_ULONG (color); - bg_color.green = GREEN16_FROM_ULONG (color); - bg_color.blue = BLUE16_FROM_ULONG (color); - -#if TARGET_API_MAC_CARBON - SetWindowContentColor (w, &bg_color); -#else - if (GetAuxWin (w, &aw_handle)) - { - ctab_handle = (*aw_handle)->awCTable; - HandToHand ((Handle *) &ctab_handle); - ct_table = (*ctab_handle)->ctTable; - ct_size = (*ctab_handle)->ctSize; - while (ct_size > -1) - { - if (ct_table->value == 0) - { - ct_table->rgb = bg_color; - CTabChanged (ctab_handle); - SetWinColor (w, (WCTabHandle) ctab_handle); - } - ct_size--; - } - } -#endif -} - -/* Flush display of frame F, or of all frames if F is null. */ - -static void -x_flush (f) - struct frame *f; -{ -#if TARGET_API_MAC_CARBON - BLOCK_INPUT; -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - if (f) - QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL); - else - QDFlushPortBuffer (GetQDGlobalsThePort (), NULL); - UNBLOCK_INPUT; -#endif -} - - /* Remove calls to XFlush by defining XFlush to an empty replacement. Calls to XFlush should be unnecessary because the X output buffer is flushed automatically as needed by calls to XPending, @@ -1923,16 +1743,6 @@ x_flush (f) #define XFlush(DISPLAY) (void) 0 -#if USE_CG_DRAWING -static void -mac_flush_display_optional (f) - struct frame *f; -{ - BLOCK_INPUT; - mac_prepare_for_quickdraw (f); - UNBLOCK_INPUT; -} -#endif /*********************************************************************** Starting and ending an update @@ -1947,17 +1757,9 @@ static void x_update_begin (f) struct frame *f; { -#if TARGET_API_MAC_CARBON - /* During update of a frame, availability of input events is - periodically checked with ReceiveNextEvent if - redisplay-dont-pause is nil. That normally flushes window buffer - changes for every check, and thus screen update looks waving even - if no input is available. So we disable screen updates during - update of a frame. */ BLOCK_INPUT; - DisableScreenUpdates (); + mac_update_begin (f); UNBLOCK_INPUT; -#endif } @@ -2095,9 +1897,7 @@ x_update_end (f) FRAME_MAC_DISPLAY_INFO (f)->mouse_face_defer = 0; BLOCK_INPUT; -#if TARGET_API_MAC_CARBON - EnableScreenUpdates (); -#endif + mac_update_end (f); XFlush (FRAME_MAC_DISPLAY (f)); UNBLOCK_INPUT; } @@ -2126,6 +1926,8 @@ XTframe_up_to_date (f) dpyinfo->mouse_face_deferred_gc = 0; UNBLOCK_INPUT; } + + mac_frame_up_to_date (f); } } @@ -2881,10 +2683,7 @@ mac_compute_glyph_string_overhangs (s) Rect r; MacFontStruct *font = s->font; -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (s->f); -#endif - SetPortWindowPort (FRAME_MAC_WINDOW (s->f)); + mac_begin_clip (s->f, NULL); TextFont (font->mac_fontnum); TextSize (font->mac_fontsize); @@ -2892,6 +2691,8 @@ mac_compute_glyph_string_overhangs (s) QDTextBounds (s->nchars * 2, (char *)s->char2b, &r); + mac_end_clip (s->f, NULL); + s->right_overhang = r.right > s->width ? r.right - s->width : 0; s->left_overhang = r.left < 0 ? -r.left : 0; } @@ -4250,7 +4051,7 @@ XTring_bell () #endif { BLOCK_INPUT; - SysBeep (1); + mac_alert_sound_play (); XFlush (FRAME_MAC_DISPLAY (f)); UNBLOCK_INPUT; } @@ -4407,7 +4208,7 @@ x_new_focus_frame (dpyinfo, frame) If FRAME has focus and there exists more than one frame, puts a FOCUS_IN_EVENT into *BUFP. */ -static void +void mac_focus_changed (type, dpyinfo, frame, bufp) int type; struct mac_display_info *dpyinfo; @@ -4442,29 +4243,6 @@ mac_focus_changed (type, dpyinfo, frame, bufp) } } -/* The focus may have changed. Figure out if it is a real focus change, - by checking both FocusIn/Out and Enter/LeaveNotify events. - - Returns FOCUS_IN_EVENT event in *BUFP. */ - -static void -x_detect_focus_change (dpyinfo, event, bufp) - struct mac_display_info *dpyinfo; - const EventRecord *event; - struct input_event *bufp; -{ - struct frame *frame; - - frame = mac_window_to_frame ((WindowRef) event->message); - if (! frame) - return; - - /* On Mac, this is only called from focus events, so no switch needed. */ - mac_focus_changed ((event->modifiers & activeFlag), - dpyinfo, frame, bufp); -} - - /* Handle an event saying the mouse has moved out of an Emacs frame. */ void @@ -4553,27 +4331,20 @@ x_get_keysym_name (keysym) static Point last_mouse_motion_position; static Lisp_Object last_mouse_motion_frame; -static int +int note_mouse_movement (frame, pos) FRAME_PTR frame; Point *pos; { struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame); -#if TARGET_API_MAC_CARBON Rect r; -#endif last_mouse_movement_time = TickCount () * (1000 / 60); /* to milliseconds */ last_mouse_motion_position = *pos; XSETFRAME (last_mouse_motion_frame, frame); if (frame == dpyinfo->mouse_face_mouse_frame -#if TARGET_API_MAC_CARBON - && !PtInRect (*pos, GetWindowPortBounds (FRAME_MAC_WINDOW (frame), &r)) -#else - && !PtInRect (*pos, &FRAME_MAC_WINDOW (frame)->portRect) -#endif - ) + && !PtInRect (*pos, mac_get_frame_bounds (frame, &r))) { /* This case corresponds to LeaveNotify in X11. If we move outside the frame, then we're certainly no longer on any text @@ -4619,7 +4390,7 @@ redo_mouse_highlight () } -static struct frame * +struct frame * mac_focus_frame (dpyinfo) struct mac_display_info *dpyinfo; { @@ -4695,14 +4466,7 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) the frame are divided into. */ Point mouse_pos; -#if TARGET_API_MAC_CARBON - GetGlobalMouse (&mouse_pos); - mouse_pos.h -= f1->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f1); - mouse_pos.v -= f1->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f1); -#else - SetPortWindowPort (FRAME_MAC_WINDOW (f1)); - GetMouse (&mouse_pos); -#endif + mac_get_frame_mouse (f1, &mouse_pos); remember_mouse_glyph (f1, mouse_pos.h, mouse_pos.v, &last_mouse_glyph); last_mouse_glyph_frame = f1; @@ -4719,305 +4483,6 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) UNBLOCK_INPUT; } - -/************************************************************************ - Toolkit scroll bars - ************************************************************************/ - -#ifdef USE_TOOLKIT_SCROLL_BARS - -static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *)); -static OSStatus install_scroll_bar_timer P_ ((void)); -static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval)); -static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode)); -static void construct_scroll_bar_click P_ ((struct scroll_bar *, int, - struct input_event *)); -static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode, - Rect *)); -static void x_scroll_bar_handle_press P_ ((struct scroll_bar *, - ControlPartCode, Point, - struct input_event *)); -static void x_scroll_bar_handle_release P_ ((struct scroll_bar *, - struct input_event *)); -static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *, - Point, struct input_event *)); -static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *, - int, int, int)); - -/* Last scroll bar part sent in x_scroll_bar_handle_*. */ - -static int last_scroll_bar_part; - -static EventLoopTimerRef scroll_bar_timer; - -static int scroll_bar_timer_event_posted_p; - -#define SCROLL_BAR_FIRST_DELAY 0.5 -#define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15) - -static pascal void -scroll_bar_timer_callback (timer, data) - EventLoopTimerRef timer; - void *data; -{ - OSStatus err; - - err = mac_post_mouse_moved_event (); - if (err == noErr) - scroll_bar_timer_event_posted_p = 1; -} - -static OSStatus -install_scroll_bar_timer () -{ - static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL; - - if (scroll_bar_timer_callbackUPP == NULL) - scroll_bar_timer_callbackUPP = - NewEventLoopTimerUPP (scroll_bar_timer_callback); - - if (scroll_bar_timer == NULL) - /* Mac OS X and CarbonLib 1.5 and later allow us to specify - kEventDurationForever as delays. */ - return - InstallEventLoopTimer (GetCurrentEventLoop (), - kEventDurationForever, kEventDurationForever, - scroll_bar_timer_callbackUPP, NULL, - &scroll_bar_timer); -} - -static OSStatus -set_scroll_bar_timer (delay) - EventTimerInterval delay; -{ - if (scroll_bar_timer == NULL) - install_scroll_bar_timer (); - - scroll_bar_timer_event_posted_p = 0; - - return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay); -} - -static int -control_part_code_to_scroll_bar_part (part_code) - ControlPartCode part_code; -{ - switch (part_code) - { - case kControlUpButtonPart: return scroll_bar_up_arrow; - case kControlDownButtonPart: return scroll_bar_down_arrow; - case kControlPageUpPart: return scroll_bar_above_handle; - case kControlPageDownPart: return scroll_bar_below_handle; - case kControlIndicatorPart: return scroll_bar_handle; - } - - return -1; -} - -static void -construct_scroll_bar_click (bar, part, bufp) - struct scroll_bar *bar; - int part; - struct input_event *bufp; -{ - bufp->kind = SCROLL_BAR_CLICK_EVENT; - bufp->frame_or_window = bar->window; - bufp->arg = Qnil; - bufp->part = part; - bufp->code = 0; - XSETINT (bufp->x, 0); - XSETINT (bufp->y, 0); - bufp->modifiers = 0; -} - -static OSStatus -get_control_part_bounds (ch, part_code, rect) - ControlRef ch; - ControlPartCode part_code; - Rect *rect; -{ - RgnHandle region = NewRgn (); - OSStatus err; - - err = GetControlRegion (ch, part_code, region); - if (err == noErr) - GetRegionBounds (region, rect); - DisposeRgn (region); - - return err; -} - -static void -x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp) - struct scroll_bar *bar; - ControlPartCode part_code; - Point mouse_pos; - struct input_event *bufp; -{ - int part = control_part_code_to_scroll_bar_part (part_code); - - if (part < 0) - return; - - if (part != scroll_bar_handle) - { - construct_scroll_bar_click (bar, part, bufp); - HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code); - set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY); - bar->dragging = Qnil; - } - else - { - Rect r; - - get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar), - kControlIndicatorPart, &r); - XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1); - } - - last_scroll_bar_part = part; - tracked_scroll_bar = bar; -} - -static void -x_scroll_bar_handle_release (bar, bufp) - struct scroll_bar *bar; - struct input_event *bufp; -{ - if (last_scroll_bar_part != scroll_bar_handle - || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0)) - construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp); - - HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0); - set_scroll_bar_timer (kEventDurationForever); - - last_scroll_bar_part = -1; - bar->dragging = Qnil; - tracked_scroll_bar = NULL; -} - -static void -x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp) - WindowRef win; - struct scroll_bar *bar; - Point mouse_pos; - struct input_event *bufp; -{ - ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); - - if (last_scroll_bar_part == scroll_bar_handle) - { - int top, top_range; - Rect r; - - get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar), - kControlIndicatorPart, &r); - - if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0) - XSETINT (bar->dragging, - (XINT (bar->dragging) + 1)); - - top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top); - top_range = XINT (bar->track_height) - XINT (bar->min_handle); - - if (top < 0) - top = 0; - if (top > top_range) - top = top_range; - - construct_scroll_bar_click (bar, scroll_bar_handle, bufp); - XSETINT (bufp->x, top); - XSETINT (bufp->y, top_range); - } - else - { - ControlPartCode part_code; - int unhilite_p = 0, part; - - if (ch != FindControlUnderMouse (mouse_pos, win, &part_code)) - unhilite_p = 1; - else - { - part = control_part_code_to_scroll_bar_part (part_code); - - switch (last_scroll_bar_part) - { - case scroll_bar_above_handle: - case scroll_bar_below_handle: - if (part != scroll_bar_above_handle - && part != scroll_bar_below_handle) - unhilite_p = 1; - break; - - case scroll_bar_up_arrow: - case scroll_bar_down_arrow: - if (part != scroll_bar_up_arrow - && part != scroll_bar_down_arrow) - unhilite_p = 1; - break; - } - } - - if (unhilite_p) - HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0); - else if (part != last_scroll_bar_part - || scroll_bar_timer_event_posted_p) - { - construct_scroll_bar_click (bar, part, bufp); - last_scroll_bar_part = part; - HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code); - set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY); - } - } -} - -/* Set the thumb size and position of scroll bar BAR. We are currently - displaying PORTION out of a whole WHOLE, and our position POSITION. */ - -static void -x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole) - struct scroll_bar *bar; - int portion, position, whole; -{ - ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); - int value, viewsize, maximum; - - if (XINT (bar->track_height) == 0) - return; - - if (whole <= portion) - value = 0, viewsize = 1, maximum = 0; - else - { - float scale; - - maximum = XINT (bar->track_height) - XINT (bar->min_handle); - scale = (float) maximum / (whole - portion); - value = position * scale + 0.5f; - viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle); - } - - BLOCK_INPUT; - - if (GetControlViewSize (ch) != viewsize - || GetControl32BitValue (ch) != value - || GetControl32BitMaximum (ch) != maximum) - { - /* Temporarily hide the scroll bar to avoid multiple redraws. */ - SetControlVisibility (ch, false, false); - - SetControl32BitMaximum (ch, maximum); - SetControl32BitValue (ch, value); - SetControlViewSize (ch, viewsize); - - SetControlVisibility (ch, true, true); - } - - UNBLOCK_INPUT; -} - -#endif /* USE_TOOLKIT_SCROLL_BARS */ - - /************************************************************************ Scroll bars, general @@ -5037,49 +4502,27 @@ x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height) struct scroll_bar *bar = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil)); Rect r; - ControlRef ch; BLOCK_INPUT; - r.left = left; - r.top = disp_top; - r.right = left + width; - r.bottom = disp_top + disp_height; - -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif -#if TARGET_API_MAC_CARBON - ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", -#ifdef USE_TOOLKIT_SCROLL_BARS - false, -#else - width < disp_height, -#endif - 0, 0, 0, kControlScrollBarProc, (long) bar); -#else - ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height, - 0, 0, 0, scrollBarProc, (long) bar); -#endif - SET_SCROLL_BAR_CONTROL_REF (bar, ch); - XSETWINDOW (bar->window, w); XSETINT (bar->top, top); XSETINT (bar->left, left); XSETINT (bar->width, width); XSETINT (bar->height, height); - XSETINT (bar->start, 0); - XSETINT (bar->end, 0); - bar->dragging = Qnil; #ifdef MAC_OSX bar->fringe_extended_p = Qnil; #endif bar->redraw_needed_p = Qnil; + + SetRect (&r, left, disp_top, left + width, disp_top + disp_height); + mac_create_scroll_bar (bar, &r, #ifdef USE_TOOLKIT_SCROLL_BARS - bar->track_top = Qnil; - bar->track_height = Qnil; - bar->min_handle = Qnil; + false +#else + width < disp_height #endif + ); /* Add bar to its frame's list of scroll bars. */ bar->next = FRAME_SCROLL_BARS (f); @@ -5093,82 +4536,6 @@ x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height) } -/* Draw BAR's handle in the proper position. - - If the handle is already drawn from START to END, don't bother - redrawing it, unless REBUILD is non-zero; in that case, always - redraw it. (REBUILD is handy for drawing the handle after expose - events.) - - Normally, we want to constrain the start and end of the handle to - fit inside its rectangle, but if the user is dragging the scroll - bar handle, we want to let them drag it down all the way, so that - the bar's top is as far down as it goes; otherwise, there's no way - to move to the very end of the buffer. */ - -#ifndef USE_TOOLKIT_SCROLL_BARS - -static void -x_scroll_bar_set_handle (bar, start, end, rebuild) - struct scroll_bar *bar; - int start, end; - int rebuild; -{ - int dragging = ! NILP (bar->dragging); - ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); - FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); - int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)); - int length = end - start; - - /* If the display is already accurate, do nothing. */ - if (! rebuild - && start == XINT (bar->start) - && end == XINT (bar->end)) - return; - - BLOCK_INPUT; - - /* Make sure the values are reasonable, and try to preserve the - distance between start and end. */ - if (start < 0) - start = 0; - else if (start > top_range) - start = top_range; - end = start + length; - - if (end < start) - end = start; - else if (end > top_range && ! dragging) - end = top_range; - - /* Store the adjusted setting in the scroll bar. */ - XSETINT (bar->start, start); - XSETINT (bar->end, end); - - /* Clip the end position, just for display. */ - if (end > top_range) - end = top_range; - - /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below - top positions, to make sure the handle is always at least that - many pixels tall. */ - end += VERTICAL_SCROLL_BAR_MIN_HANDLE; - - SetControlMinimum (ch, 0); - /* Don't inadvertently activate deactivated scroll bars */ - if (GetControlMaximum (ch) != -1) - SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE - - (end - start)); - SetControlValue (ch, start); -#if TARGET_API_MAC_CARBON - SetControlViewSize (ch, end - start); -#endif - - UNBLOCK_INPUT; -} - -#endif /* !USE_TOOLKIT_SCROLL_BARS */ - /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to nil. */ @@ -5176,15 +4543,10 @@ static void x_scroll_bar_remove (bar) struct scroll_bar *bar; { - FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); - BLOCK_INPUT; -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif /* Destroy the Mac scroll bar control */ - DisposeControl (SCROLL_BAR_CONTROL_REF (bar)); + mac_dispose_scroll_bar (bar); /* Disassociate this scroll bar from its window. */ XWINDOW (bar->window)->vertical_scroll_bar = Qnil; @@ -5283,10 +4645,7 @@ XTset_vertical_scroll_bar (w, portion, whole, position) else { /* It may just need to be moved and resized. */ - ControlRef ch; - bar = XSCROLL_BAR (w->vertical_scroll_bar); - ch = SCROLL_BAR_CONTROL_REF (bar); BLOCK_INPUT; @@ -5301,15 +4660,12 @@ XTset_vertical_scroll_bar (w, portion, whole, position) ) { if (!NILP (bar->redraw_needed_p)) - { -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - Draw1Control (SCROLL_BAR_CONTROL_REF (bar)); - } + mac_redraw_scroll_bar (bar); } else { + Rect r; + /* Since toolkit scroll bars are smaller than the space reserved for them on the frame, we have to clear "under" them. */ #ifdef MAC_OSX @@ -5319,28 +4675,16 @@ XTset_vertical_scroll_bar (w, portion, whole, position) #endif mac_clear_area (f, left, top, width, height); -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - HideControl (ch); - MoveControl (ch, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top); - SizeControl (ch, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, - disp_height); -#ifndef USE_TOOLKIT_SCROLL_BARS - if (sb_width < disp_height) - ShowControl (ch); -#endif + SetRect (&r, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, disp_top, + sb_left + sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM, + disp_top + disp_height); + mac_set_scroll_bar_bounds (bar, &r); /* Remember new settings. */ XSETINT (bar->left, sb_left); XSETINT (bar->top, top); XSETINT (bar->width, sb_width); XSETINT (bar->height, height); -#ifdef USE_TOOLKIT_SCROLL_BARS - bar->track_top = Qnil; - bar->track_height = Qnil; - bar->min_handle = Qnil; -#endif } UNBLOCK_INPUT; @@ -5352,51 +4696,6 @@ XTset_vertical_scroll_bar (w, portion, whole, position) bar->redraw_needed_p = Qnil; #ifdef USE_TOOLKIT_SCROLL_BARS - if (NILP (bar->track_top)) - { - if (sb_width >= disp_height -#ifdef MAC_OSX - || sb_width < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH -#endif - ) - { - XSETINT (bar->track_top, 0); - XSETINT (bar->track_height, 0); - XSETINT (bar->min_handle, 0); - } - else - { - ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); - Rect r0, r1; - - BLOCK_INPUT; - - SetControl32BitMinimum (ch, 0); - SetControl32BitMaximum (ch, 1 << 30); - SetControlViewSize (ch, 1); - - /* Move the scroll bar thumb to the top. */ - SetControl32BitValue (ch, 0); - get_control_part_bounds (ch, kControlIndicatorPart, &r0); - - /* Move the scroll bar thumb to the bottom. */ - SetControl32BitValue (ch, 1 << 30); - get_control_part_bounds (ch, kControlIndicatorPart, &r1); - - UnionRect (&r0, &r1, &r0); - XSETINT (bar->track_top, r0.top); - XSETINT (bar->track_height, r0.bottom - r0.top); - XSETINT (bar->min_handle, r1.bottom - r1.top); - - /* Don't show the scroll bar if its height is not enough to - display the scroll bar thumb. */ - if (r0.bottom - r0.top > 0) - ShowControl (ch); - - UNBLOCK_INPUT; - } - } - x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole); #else /* not USE_TOOLKIT_SCROLL_BARS */ /* Set the scroll bar's current state, unless we're currently being @@ -5524,181 +4823,6 @@ XTjudge_scroll_bars (f) and they should get garbage-collected. */ } - -/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind - is set to something other than NO_EVENT, it is enqueued. - - This may be called from a signal handler, so we have to ignore GC - mark bits. */ - -static void -x_scroll_bar_handle_click (bar, part_code, er, bufp) - struct scroll_bar *bar; - ControlPartCode part_code; - const EventRecord *er; - struct input_event *bufp; -{ - int win_y, top_range; - - if (! GC_WINDOWP (bar->window)) - abort (); - - bufp->kind = SCROLL_BAR_CLICK_EVENT; - bufp->frame_or_window = bar->window; - bufp->arg = Qnil; - - bar->dragging = Qnil; - - switch (part_code) - { - case kControlUpButtonPart: - bufp->part = scroll_bar_up_arrow; - break; - case kControlDownButtonPart: - bufp->part = scroll_bar_down_arrow; - break; - case kControlPageUpPart: - bufp->part = scroll_bar_above_handle; - break; - case kControlPageDownPart: - bufp->part = scroll_bar_below_handle; - break; -#if TARGET_API_MAC_CARBON - default: -#else - case kControlIndicatorPart: -#endif - if (er->what == mouseDown) - bar->dragging = make_number (0); - XSETVECTOR (last_mouse_scroll_bar, bar); - bufp->part = scroll_bar_handle; - break; - } - - win_y = XINT (bufp->y) - XINT (bar->top); - top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height)); - - win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER; - - win_y -= 24; - - if (! NILP (bar->dragging)) - win_y -= XINT (bar->dragging); - - if (win_y < 0) - win_y = 0; - if (win_y > top_range) - win_y = top_range; - - XSETINT (bufp->x, win_y); - XSETINT (bufp->y, top_range); -} - -#ifndef USE_TOOLKIT_SCROLL_BARS - -/* Handle some mouse motion while someone is dragging the scroll bar. - - This may be called from a signal handler, so we have to ignore GC - mark bits. */ - -static void -x_scroll_bar_note_movement (bar, y_pos, t) - struct scroll_bar *bar; - int y_pos; - Time t; -{ - FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame); - - last_mouse_movement_time = t; - - f->mouse_moved = 1; - XSETVECTOR (last_mouse_scroll_bar, bar); - - /* If we're dragging the bar, display it. */ - if (! GC_NILP (bar->dragging)) - { - /* Where should the handle be now? */ - int new_start = y_pos - 24; - - if (new_start != XINT (bar->start)) - { - int new_end = new_start + (XINT (bar->end) - XINT (bar->start)); - - x_scroll_bar_set_handle (bar, new_start, new_end, 0); - } - } -} - -#endif /* !USE_TOOLKIT_SCROLL_BARS */ - -/* Return information to the user about the current position of the mouse - on the scroll bar. */ - -static void -x_scroll_bar_report_motion (fp, bar_window, part, x, y, time) - FRAME_PTR *fp; - Lisp_Object *bar_window; - enum scroll_bar_part *part; - Lisp_Object *x, *y; - unsigned long *time; -{ - struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar); - ControlRef ch = SCROLL_BAR_CONTROL_REF (bar); -#if TARGET_API_MAC_CARBON - WindowRef wp = GetControlOwner (ch); -#else - WindowRef wp = (*ch)->contrlOwner; -#endif - Point mouse_pos; - struct frame *f = mac_window_to_frame (wp); - int win_y, top_range; - -#if TARGET_API_MAC_CARBON - GetGlobalMouse (&mouse_pos); - mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); - mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); -#else - SetPortWindowPort (wp); - GetMouse (&mouse_pos); -#endif - - win_y = mouse_pos.v - XINT (bar->top); - top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height)); - - win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER; - - win_y -= 24; - - if (! NILP (bar->dragging)) - win_y -= XINT (bar->dragging); - - if (win_y < 0) - win_y = 0; - if (win_y > top_range) - win_y = top_range; - - *fp = f; - *bar_window = bar->window; - - if (! NILP (bar->dragging)) - *part = scroll_bar_handle; - else if (win_y < XINT (bar->start)) - *part = scroll_bar_above_handle; - else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE) - *part = scroll_bar_handle; - else - *part = scroll_bar_below_handle; - - XSETINT (*x, win_y); - XSETINT (*y, top_range); - - f->mouse_moved = 0; - last_mouse_scroll_bar = Qnil; - - *time = last_mouse_movement_time; -} - - /* The screen has been cleared so we may have changed foreground or background colors, and the scroll bars may need to be redrawn. Clear out the scroll bars, and ask for expose events, so we can @@ -5724,27 +4848,7 @@ x_scroll_bar_clear (f) Tool-bars ***********************************************************************/ #if USE_MAC_TOOLBAR - -/* In identifiers such as function/variable names, Emacs tool bar is - referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */ - -#define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar")) -#define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon")) - -#define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0' -#define TOOLBAR_ITEM_COMMAND_ID_P(id) \ - (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET) -#define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \ - ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET) -#define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \ - ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET) - -static int mac_event_to_emacs_modifiers P_ ((EventRef)); -static void mac_handle_origin_change P_ ((struct frame *)); -static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef, - EventRef, void *)); - -static void +void mac_move_window_with_gravity (f, win_gravity, left, top) struct frame *f; int win_gravity; @@ -5796,10 +4900,10 @@ mac_move_window_with_gravity (f, win_gravity, left, top) break; } - MoveWindow (FRAME_MAC_WINDOW (f), left, top, false); + mac_move_window (FRAME_MAC_WINDOW (f), left, top, false); } -static void +void mac_get_window_origin_with_gravity (f, win_gravity, left, top) struct frame *f; int win_gravity; @@ -5854,65 +4958,7 @@ mac_get_window_origin_with_gravity (f, win_gravity, left, top) } } -static OSStatus -mac_handle_toolbar_event (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - OSStatus err, result = eventNotHandledErr; - - switch (GetEventKind (event)) - { - case kEventToolbarGetDefaultIdentifiers: - result = noErr; - break; - - case kEventToolbarGetAllowedIdentifiers: - { - CFMutableArrayRef array; - - GetEventParameter (event, kEventParamMutableArray, - typeCFMutableArrayRef, NULL, - sizeof (CFMutableArrayRef), NULL, &array); - CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER); - result = noErr; - } - break; - - case kEventToolbarCreateItemWithIdentifier: - { - CFStringRef identifier; - HIToolbarItemRef item = NULL; - - GetEventParameter (event, kEventParamToolbarItemIdentifier, - typeCFStringRef, NULL, - sizeof (CFStringRef), NULL, &identifier); - - if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0) - == kCFCompareEqualTo) - HIToolbarItemCreate (identifier, - kHIToolbarItemAllowDuplicates - | kHIToolbarItemCantBeRemoved, &item); - - if (item) - { - SetEventParameter (event, kEventParamToolbarItem, - typeHIToolbarItemRef, - sizeof (HIToolbarItemRef), &item); - result = noErr; - } - } - break; - - default: - abort (); - } - - return result; -} - -static CGImageRef +CGImageRef mac_image_spec_to_cg_image (f, image) struct frame *f; Lisp_Object image; @@ -5929,341 +4975,6 @@ mac_image_spec_to_cg_image (f, image) return img->data.ptr_val; } } - -/* Create a tool bar for frame F. */ - -static OSStatus -mac_create_frame_tool_bar (f) - FRAME_PTR f; -{ - OSStatus err; - HIToolbarRef toolbar; - - err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes, - &toolbar); - if (err == noErr) - { - static const EventTypeSpec specs[] = - {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers}, - {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers}, - {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}}; - - err = InstallEventHandler (HIObjectGetEventTarget (toolbar), - mac_handle_toolbar_event, - GetEventTypeCount (specs), specs, - f, NULL); - } - - if (err == noErr) - err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly); - if (err == noErr) - { - static const EventTypeSpec specs[] = - {{kEventClassCommand, kEventCommandProcess}}; - - err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f), - mac_handle_toolbar_command_event, - GetEventTypeCount (specs), - specs, f, NULL); - } - if (err == noErr) - err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar); - - if (toolbar) - CFRelease (toolbar); - - return err; -} - -/* Update the tool bar for frame F. Add new buttons and remove old. */ - -void -update_frame_tool_bar (f) - FRAME_PTR f; -{ - HIToolbarRef toolbar = NULL; - short left, top; - CFArrayRef old_items = NULL; - CFIndex old_count; - int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity; - struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); - - BLOCK_INPUT; - - GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar); - if (toolbar == NULL) - { - mac_create_frame_tool_bar (f); - GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar); - if (toolbar == NULL) - goto out; - if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity) - mac_get_window_origin_with_gravity (f, win_gravity, &left, &top); - } - - HIToolbarCopyItems (toolbar, &old_items); - if (old_items == NULL) - goto out; - - old_count = CFArrayGetCount (old_items); - pos = 0; - for (i = 0; i < f->n_tool_bar_items; ++i) - { -#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX)) - - int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)); - int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)); - int idx; - Lisp_Object image; - CGImageRef cg_image; - CFStringRef label; - HIToolbarItemRef item; - - /* If image is a vector, choose the image according to the - button state. */ - image = PROP (TOOL_BAR_ITEM_IMAGES); - if (VECTORP (image)) - { - if (enabled_p) - idx = (selected_p - ? TOOL_BAR_IMAGE_ENABLED_SELECTED - : TOOL_BAR_IMAGE_ENABLED_DESELECTED); - else - idx = (selected_p - ? TOOL_BAR_IMAGE_DISABLED_SELECTED - : TOOL_BAR_IMAGE_DISABLED_DESELECTED); - - xassert (ASIZE (image) >= idx); - image = AREF (image, idx); - } - else - idx = -1; - - cg_image = mac_image_spec_to_cg_image (f, image); - /* Ignore invalid image specifications. */ - if (cg_image == NULL) - continue; - - label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION)); - if (label == NULL) - label = CFSTR (""); - - if (pos < old_count) - { - CGImageRef old_cg_image = NULL; - CFStringRef old_label = NULL; - Boolean old_enabled_p; - - item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos); - - HIToolbarItemCopyImage (item, &old_cg_image); - if (cg_image != old_cg_image) - HIToolbarItemSetImage (item, cg_image); - CGImageRelease (old_cg_image); - - HIToolbarItemCopyLabel (item, &old_label); - if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo) - HIToolbarItemSetLabel (item, label); - CFRelease (old_label); - - old_enabled_p = HIToolbarItemIsEnabled (item); - if ((enabled_p || idx >= 0) != old_enabled_p) - HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0)); - } - else - { - item = NULL; - HIToolbarCreateItemWithIdentifier (toolbar, - TOOLBAR_ICON_ITEM_IDENTIFIER, - NULL, &item); - if (item) - { - HIToolbarItemSetImage (item, cg_image); - HIToolbarItemSetLabel (item, label); - HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0)); - HIToolbarAppendItem (toolbar, item); - CFRelease (item); - } - } - - CFRelease (label); - if (item) - { - HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i)); - pos++; - } - } - - CFRelease (old_items); - - while (pos < old_count) - HIToolbarRemoveItemAtIndex (toolbar, --old_count); - - ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true, - !win_gravity && f == mac_focus_frame (dpyinfo)); - /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on - toolbar visibility change. */ - mac_handle_origin_change (f); - if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity) - { - mac_move_window_with_gravity (f, win_gravity, left, top); - /* If the title bar is completely outside the screen, adjust the - position. */ - ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, - kWindowConstrainMoveRegardlessOfFit - | kWindowConstrainAllowPartial, NULL, NULL); - f->output_data.mac->toolbar_win_gravity = 0; - } - - out: - UNBLOCK_INPUT; -} - -/* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it - doesn't deallocate the resources. */ - -void -free_frame_tool_bar (f) - FRAME_PTR f; -{ - if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f))) - { - struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); - - BLOCK_INPUT; - ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false, - (NILP (find_symbol_value - (intern ("frame-notice-user-settings"))) - && f == mac_focus_frame (dpyinfo))); - /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events - on toolbar visibility change. */ - mac_handle_origin_change (f); - UNBLOCK_INPUT; - } -} - -static void -mac_tool_bar_note_mouse_movement (f, event) - struct frame *f; - EventRef event; -{ - OSStatus err; - struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); - int mouse_down_p; - WindowRef window; - WindowPartCode part_code; - HIViewRef item_view; - UInt32 command_id; - - mouse_down_p = (dpyinfo->grabbed - && f == last_mouse_frame - && FRAME_LIVE_P (f)); - if (mouse_down_p) - return; - - err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef, NULL, - sizeof (WindowRef), NULL, &window); - if (err != noErr || window != FRAME_MAC_WINDOW (f)) - return; - - err = GetEventParameter (event, kEventParamWindowPartCode, - typeWindowPartCode, NULL, - sizeof (WindowPartCode), NULL, &part_code); - if (err != noErr || part_code != inStructure) - return; - - err = HIViewGetViewForMouseEvent (HIViewGetRoot (window), event, &item_view); - /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a - toolbar item view seems to have the same command ID with that of - the toolbar item. */ - if (err == noErr) - err = GetControlCommandID (item_view, &command_id); - if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id)) - { - int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id); - - if (i < f->n_tool_bar_items) - { - HIRect bounds; - HIViewRef content_view; - - err = HIViewGetBounds (item_view, &bounds); - if (err == noErr) - err = HIViewFindByID (HIViewGetRoot (window), - kHIViewWindowContentID, &content_view); - if (err == noErr) - err = HIViewConvertRect (&bounds, item_view, content_view); - if (err == noErr) - SetRect (&last_mouse_glyph, - CGRectGetMinX (bounds), CGRectGetMinY (bounds), - CGRectGetMaxX (bounds), CGRectGetMaxY (bounds)); - - help_echo_object = help_echo_window = Qnil; - help_echo_pos = -1; - help_echo_string = PROP (TOOL_BAR_ITEM_HELP); - if (NILP (help_echo_string)) - help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION); - } - } -} - -static OSStatus -mac_handle_toolbar_command_event (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - OSStatus err, result = eventNotHandledErr; - struct frame *f = (struct frame *) data; - HICommand command; - - err = GetEventParameter (event, kEventParamDirectObject, - typeHICommand, NULL, - sizeof (HICommand), NULL, &command); - if (err != noErr) - return result; - - switch (GetEventKind (event)) - { - case kEventCommandProcess: - if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID)) - result = CallNextEventHandler (next_handler, event); - else - { - int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID); - - if (i < f->n_tool_bar_items - && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P))) - { - Lisp_Object frame; - struct input_event buf; - - EVENT_INIT (buf); - - XSETFRAME (frame, f); - buf.kind = TOOL_BAR_EVENT; - buf.frame_or_window = frame; - buf.arg = frame; - kbd_buffer_store_event (&buf); - - buf.kind = TOOL_BAR_EVENT; - buf.frame_or_window = frame; - buf.arg = PROP (TOOL_BAR_ITEM_KEY); - buf.modifiers = mac_event_to_emacs_modifiers (event); - kbd_buffer_store_event (&buf); - - result = noErr; - } - } - break; - - default: - abort (); - } -#undef PROP - - return result; -} #endif /* USE_MAC_TOOLBAR */ @@ -6691,32 +5402,13 @@ xim_close_dpy (dpyinfo) void -mac_get_window_bounds (f, inner, outer) - struct frame *f; - Rect *inner, *outer; -{ -#if TARGET_API_MAC_CARBON - GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner); - GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer); -#else /* not TARGET_API_MAC_CARBON */ - RgnHandle region = NewRgn (); - - GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region); - *inner = (*region)->rgnBBox; - GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region); - *outer = (*region)->rgnBBox; - DisposeRgn (region); -#endif /* not TARGET_API_MAC_CARBON */ -} - -static void mac_handle_origin_change (f) struct frame *f; { x_real_positions (f, &f->left_pos, &f->top_pos); } -static void +void mac_handle_size_change (f, pixelwidth, pixelheight) struct frame *f; int pixelwidth, pixelheight; @@ -6749,14 +5441,7 @@ mac_handle_size_change (f, pixelwidth, pixelheight) cancel_mouse_face (f); #if TARGET_API_MAC_CARBON - if (f->output_data.mac->hourglass_control) - { -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - MoveControl (f->output_data.mac->hourglass_control, - pixelwidth - HOURGLASS_WIDTH, 0); - } + mac_reposition_hourglass (f); #endif } } @@ -6836,7 +5521,7 @@ x_set_offset (f, xoff, yoff, change_gravity) x_wm_set_size_hint (f, (long) 0, 0); #if TARGET_API_MAC_CARBON - MoveWindowStructure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos); + mac_move_window_structure (FRAME_MAC_WINDOW (f), f->left_pos, f->top_pos); /* If the title bar is completely outside the screen, adjust the position. */ ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn, @@ -6916,7 +5601,7 @@ x_set_window_size (f, change_gravity, cols, rows) f->win_gravity = NorthWestGravity; x_wm_set_size_hint (f, (long) 0, 0); - SizeWindow (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0); + mac_size_window (FRAME_MAC_WINDOW (f), pixelwidth, pixelheight, 0); #if TARGET_API_MAC_CARBON if (!NILP (tip_frame) && f == XFRAME (tip_frame)) @@ -6965,10 +5650,8 @@ x_set_mouse_pixel_position (f, pix_x, pix_y) int pix_x, pix_y; { #ifdef MAC_OSX - pix_x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); - pix_y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); - BLOCK_INPUT; + mac_convert_frame_point_to_global (f, &pix_x, &pix_y); CGWarpMouseCursorPosition (CGPointMake (pix_x, pix_y)); UNBLOCK_INPUT; #else @@ -7015,7 +5698,7 @@ x_raise_frame (f) if (f->async_visible) { BLOCK_INPUT; - BringToFront (FRAME_MAC_WINDOW (f)); + mac_bring_window_to_front (FRAME_MAC_WINDOW (f)); UNBLOCK_INPUT; } } @@ -7029,7 +5712,7 @@ x_lower_frame (f) if (f->async_visible) { BLOCK_INPUT; - SendBehind (FRAME_MAC_WINDOW (f), NULL); + mac_send_window_behind (FRAME_MAC_WINDOW (f), NULL); UNBLOCK_INPUT; } } @@ -7047,17 +5730,17 @@ XTframe_raise_lower (f, raise_flag) /* Change of visibility. */ -static void +void mac_handle_visibility_change (f) struct frame *f; { - WindowRef wp = FRAME_MAC_WINDOW (f); + Window wp = FRAME_MAC_WINDOW (f); int visible = 0, iconified = 0; struct input_event buf; - if (IsWindowVisible (wp)) + if (mac_is_window_visible (wp)) { - if (IsWindowCollapsed (wp)) + if (mac_is_window_collapsed (wp)) iconified = 1; else visible = 1; @@ -7123,8 +5806,8 @@ x_make_frame_visible (f) f->output_data.mac->asked_for_visible = 1; - CollapseWindow (FRAME_MAC_WINDOW (f), false); - ShowWindow (FRAME_MAC_WINDOW (f)); + mac_collapse_window (FRAME_MAC_WINDOW (f), false); + mac_show_window (FRAME_MAC_WINDOW (f)); } XFlush (FRAME_MAC_DISPLAY (f)); @@ -7202,7 +5885,7 @@ x_make_frame_invisible (f) x_wm_set_size_hint (f, (long) 0, 1); #endif - HideWindow (FRAME_MAC_WINDOW (f)); + mac_hide_window (FRAME_MAC_WINDOW (f)); UNBLOCK_INPUT; @@ -7236,9 +5919,9 @@ x_iconify_frame (f) FRAME_SAMPLE_VISIBILITY (f); if (! FRAME_VISIBLE_P (f)) - ShowWindow (FRAME_MAC_WINDOW (f)); + mac_show_window (FRAME_MAC_WINDOW (f)); - err = CollapseWindow (FRAME_MAC_WINDOW (f), true); + err = mac_collapse_window (FRAME_MAC_WINDOW (f), true); UNBLOCK_INPUT; @@ -7258,35 +5941,14 @@ x_free_frame_resources (f) struct frame *f; { struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); - WindowRef wp = FRAME_MAC_WINDOW (f); + Window wp = FRAME_MAC_WINDOW (f); BLOCK_INPUT; - if (wp != tip_window) - remove_window_handler (wp); - -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - DisposeWindow (wp); - if (wp == tip_window) - /* Neither WaitNextEvent nor ReceiveNextEvent receives `window - closed' event. So we reset tip_window here. */ - tip_window = NULL; - - free_frame_menubar (f); - - if (FRAME_FACE_CACHE (f)) - free_frame_faces (f); - - x_free_gcs (f); - - if (FRAME_SIZE_HINTS (f)) - xfree (FRAME_SIZE_HINTS (f)); - - xfree (f->output_data.mac); - f->output_data.mac = NULL; - + /* AppKit version of mac_dispose_frame_window, which is implemented + as -[NSWindow close], will change the focus to the next window + during its call. So, unlike other platforms, we clean up the + focus-related variables before calling mac_dispose_frame_window. */ if (f == dpyinfo->x_focus_frame) { dpyinfo->x_focus_frame = 0; @@ -7310,6 +5972,25 @@ x_free_frame_resources (f) dpyinfo->mouse_face_mouse_frame = 0; } + mac_dispose_frame_window (f); + if (wp == tip_window) + /* Neither WaitNextEvent nor ReceiveNextEvent receives `window + closed' event. So we reset tip_window here. */ + tip_window = NULL; + + free_frame_menubar (f); + + if (FRAME_FACE_CACHE (f)) + free_frame_faces (f); + + x_free_gcs (f); + + if (FRAME_SIZE_HINTS (f)) + xfree (FRAME_SIZE_HINTS (f)); + + xfree (f->output_data.mac); + f->output_data.mac = NULL; + UNBLOCK_INPUT; } @@ -7823,6 +6504,9 @@ static Lisp_Object atsu_font_id_hash; static Lisp_Object fm_style_face_attributes_alist; extern Lisp_Object QCfamily, QCweight, QCslant, Qnormal, Qbold, Qitalic; #endif +#if USE_MAC_FONT_PANEL +Lisp_Object Qpanel_closed, Qselection; +#endif /* Alist linking character set strings to Mac text encoding and Emacs coding system. */ @@ -8968,10 +7652,7 @@ mac_load_query_font (f, fontname) FontInfo the_fontinfo; int is_two_byte_font; -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - SetPortWindowPort (FRAME_MAC_WINDOW (f)); + mac_begin_clip (f, NULL); TextFont (fontnum); TextSize (size); @@ -9058,6 +7739,8 @@ mac_load_query_font (f, fontname) for (c = 0x21, pcm = space_bounds + 1; c <= 0xff; c++, pcm++) mac_query_char_extents (NULL, c, NULL, NULL, pcm, NULL); } + + mac_end_clip (f, NULL); } if (space_bounds) @@ -9386,158 +8069,6 @@ x_find_ccl_program (fontp) } } -#if USE_MAC_FONT_PANEL -/* Whether Font Panel has been shown before. The first call to font - panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is - slow. This variable is used for deferring such a call as much as - possible. */ -static int font_panel_shown_p = 0; - -extern Lisp_Object Qfont; -static Lisp_Object Qpanel_closed, Qselection; - -static OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID, - Lisp_Object, - Lisp_Object, - EventRef, UInt32, - const EventParamName *, - const EventParamType *)); - -int -mac_font_panel_visible_p () -{ - return font_panel_shown_p && FPIsFontPanelVisible (); -} - -static pascal OSStatus -mac_handle_font_event (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - OSStatus result, err; - Lisp_Object id_key; - int num_params; - const EventParamName *names; - const EventParamType *types; - static const EventParamName names_sel[] = {kEventParamATSUFontID, - kEventParamATSUFontSize, - kEventParamFMFontFamily, - kEventParamFMFontStyle, - kEventParamFMFontSize, - kEventParamFontColor}; - static const EventParamType types_sel[] = {typeATSUFontID, - typeATSUSize, - typeFMFontFamily, - typeFMFontStyle, - typeFMFontSize, - typeFontColor}; - - result = CallNextEventHandler (next_handler, event); - if (result != eventNotHandledErr) - return result; - - switch (GetEventKind (event)) - { - case kEventFontPanelClosed: - id_key = Qpanel_closed; - num_params = 0; - names = NULL; - types = NULL; - break; - - case kEventFontSelection: - id_key = Qselection; - num_params = sizeof (names_sel) / sizeof (names_sel[0]); - names = names_sel; - types = types_sel; - break; - } - - err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key, - event, num_params, - names, types); - if (err == noErr) - result = noErr; - - return result; -} - -OSStatus -mac_show_hide_font_panel () -{ - if (!font_panel_shown_p) - { - OSStatus err; - - static const EventTypeSpec specs[] = - {{kEventClassFont, kEventFontPanelClosed}, - {kEventClassFont, kEventFontSelection}}; - - err = InstallApplicationEventHandler (mac_handle_font_event, - GetEventTypeCount (specs), - specs, NULL, NULL); - if (err != noErr) - return err; - - font_panel_shown_p = 1; - } - - return FPShowHideFontPanel (); -} - -OSStatus -mac_set_font_info_for_selection (f, face_id, c) - struct frame *f; - int face_id, c; -{ - OSStatus err; - EventTargetRef target = NULL; - XFontStruct *font = NULL; - - if (!mac_font_panel_visible_p ()) - return noErr; - - if (f) - { - target = GetWindowEventTarget (FRAME_MAC_WINDOW (f)); - - if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0)) - { - struct face *face; - - face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c); - face = FACE_FROM_ID (f, face_id); - font = face->font; - } - } - - if (font == NULL) - err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target); - else - { - if (font->mac_fontnum != -1) - { - FontSelectionQDStyle qd_style; - - qd_style.version = kFontSelectionQDStyleVersionZero; - qd_style.instance.fontFamily = font->mac_fontnum; - qd_style.instance.fontStyle = font->mac_fontface; - qd_style.size = font->mac_fontsize; - qd_style.hasColor = false; - - err = SetFontInfoForSelection (kFontSelectionQDType, - 1, &qd_style, target); - } - else - err = SetFontInfoForSelection (kFontSelectionATSUIType, - 1, &font->mac_style, target); - } - - return err; -} -#endif - /* The Mac Event loop code */ @@ -9563,20 +8094,6 @@ mac_set_font_info_for_selection (f, face_id, c) #endif #endif /* ! TARGET_API_MAC_CARBON */ -#define M_APPLE 234 -#define I_ABOUT 1 - -#define DEFAULT_NUM_COLS 80 - -#define MIN_DOC_SIZE 64 -#define MAX_DOC_SIZE 32767 - -#define EXTRA_STACK_ALLOC (256 * 1024) - -#define ARGV_STRING_LIST_ID 129 -#define ABOUT_ALERT_ID 128 -#define RAM_TOO_LARGE_ALERT_ID 129 - /* Contains the string "reverse", which is a constant for mouse button emu.*/ Lisp_Object Qreverse; @@ -9611,70 +8128,43 @@ int mac_pass_command_to_system; int mac_pass_control_to_system; #endif -/* Points to the variable `inev' in the function XTread_socket. It is - used for passing an input event to the function back from - Carbon/Apple event handlers. */ -static struct input_event *read_socket_inev = NULL; - /* Whether or not the screen configuration has changed. */ -static int mac_screen_config_changed = 0; - -Point saved_menu_event_location; +int mac_screen_config_changed = 0; /* Apple Events */ #if TARGET_API_MAC_CARBON -static Lisp_Object Qhi_command; +Lisp_Object Qhi_command; #ifdef MAC_OSX -extern Lisp_Object Qwindow; -static Lisp_Object Qtoolbar_switch_mode; +Lisp_Object Qtoolbar_switch_mode; #endif #if USE_MAC_TSM -static TSMDocumentID tsm_document_id; -static Lisp_Object Qtext_input; -static Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event; -static Lisp_Object Vmac_ts_active_input_overlay; -extern Lisp_Object Qbefore_string; -static Lisp_Object Vmac_ts_script_language_on_focus; -static Lisp_Object saved_ts_script_language_on_focus; +Lisp_Object Qtext_input; +Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event; +Lisp_Object Vmac_ts_active_input_overlay; +Lisp_Object Vmac_ts_script_language_on_focus; +Lisp_Object saved_ts_script_language_on_focus; static ScriptLanguageRecord saved_ts_language; static Component saved_ts_component; #endif +#ifdef MAC_OSX +Lisp_Object Qservice, Qpaste, Qperform; +#endif #endif /* TARGET_API_MAC_CARBON */ -extern int mac_ready_for_apple_events; extern Lisp_Object Qundefined; +extern int XTread_socket P_ ((int, int, struct input_event *)); extern void init_apple_event_handler P_ ((void)); extern void mac_find_apple_event_spec P_ ((AEEventClass, AEEventID, Lisp_Object *, Lisp_Object *, Lisp_Object *)); extern OSErr init_coercion_handler P_ ((void)); -/* Drag and Drop */ -extern OSErr install_drag_handler P_ ((WindowRef)); -extern void remove_drag_handler P_ ((WindowRef)); - -#if TARGET_API_MAC_CARBON -/* Showing help echo string during menu tracking */ -extern OSStatus install_menu_target_item_handler P_ ((void)); - -#ifdef MAC_OSX -extern OSStatus install_service_handler (); -static Lisp_Object Qservice, Qpaste, Qperform; -#endif -#endif - -extern void init_emacs_passwd_dir (); -extern int emacs_main (int, char **, char **); - -extern void initialize_applescript(); -extern void terminate_applescript(); - /* Table for translating Mac keycode to X keysym values. Contributed by Sudhir Shenoy. Mapping for special keys is now identical to that in Apple X11 except `clear' (-> ) on the KeyPad, `enter' (-> ) on the right of the Cmd key on laptops, and fn + `enter' (-> ). */ -static const unsigned char keycode_to_xkeysym_table[] = { +const unsigned char keycode_to_xkeysym_table[] = { /*0x00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*0x20*/ 0, 0, 0, 0, 0x0d /*return*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -9743,7 +8233,7 @@ static const unsigned char fn_keycode_to_keycode_table[] = { }; #endif /* MAC_OSX */ -static int +int #if TARGET_API_MAC_CARBON mac_to_emacs_modifiers (UInt32 mods, UInt32 unmapped_mods) #else @@ -9790,7 +8280,7 @@ mac_to_emacs_modifiers (EventModifiers mods, EventModifiers unmapped_mods) return result; } -static UInt32 +UInt32 mac_mapped_modifiers (modifiers, key_code) UInt32 modifiers, key_code; { @@ -9818,7 +8308,7 @@ mac_mapped_modifiers (modifiers, key_code) return mapped_modifiers_all & modifiers; } -static int +int mac_get_emulated_btn ( UInt32 modifiers ) { int result = 0; @@ -9832,6 +8322,84 @@ mac_get_emulated_btn ( UInt32 modifiers ) return result; } +#if USE_MAC_TSM +OSStatus +mac_restore_keyboard_input_source () +{ + OSStatus err = noErr; + ScriptLanguageRecord slrec, *slptr = NULL; + + if (EQ (Vmac_ts_script_language_on_focus, Qt) + && EQ (saved_ts_script_language_on_focus, Qt)) + slptr = &saved_ts_language; + else if (CONSP (Vmac_ts_script_language_on_focus) + && INTEGERP (XCAR (Vmac_ts_script_language_on_focus)) + && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)) + && CONSP (saved_ts_script_language_on_focus) + && EQ (XCAR (saved_ts_script_language_on_focus), + XCAR (Vmac_ts_script_language_on_focus)) + && EQ (XCDR (saved_ts_script_language_on_focus), + XCDR (Vmac_ts_script_language_on_focus))) + { + slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus)); + slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus)); + slptr = &slrec; + } + + if (slptr) + { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 + err = SetDefaultInputMethodOfClass (saved_ts_component, slptr, + kKeyboardInputMethodClass); +#else + err = SetDefaultInputMethod (saved_ts_component, slptr); +#endif + if (err == noErr) + err = SetTextServiceLanguage (slptr); + + /* Seems to be needed on Mac OS X 10.2. */ + if (err == noErr) + KeyScript (slptr->fScript | smKeyForceKeyScriptMask); + } + + return err; +} + +void +mac_save_keyboard_input_source () +{ + OSStatus err; + ScriptLanguageRecord slrec, *slptr = NULL; + + saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus; + + if (EQ (Vmac_ts_script_language_on_focus, Qt)) + { + err = GetTextServiceLanguage (&saved_ts_language); + if (err == noErr) + slptr = &saved_ts_language; + } + else if (CONSP (Vmac_ts_script_language_on_focus) + && INTEGERP (XCAR (Vmac_ts_script_language_on_focus)) + && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))) + { + slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus)); + slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus)); + slptr = &slrec; + } + + if (slptr) + { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 + GetDefaultInputMethodOfClass (&saved_ts_component, slptr, + kKeyboardInputMethodClass); +#else + GetDefaultInputMethod (&saved_ts_component, slptr); +#endif + } +} +#endif + #if TARGET_API_MAC_CARBON /***** Code to handle C-g testing *****/ extern int quit_char; @@ -9865,538 +8433,6 @@ mac_quit_char_key_p (modifiers, key_code) } #endif -#if TARGET_API_MAC_CARBON -/* Obtains the event modifiers from the event ref and then calls - mac_to_emacs_modifiers. */ -static int -mac_event_to_emacs_modifiers (EventRef eventRef) -{ - UInt32 mods = 0, class; - - GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL, - sizeof (UInt32), NULL, &mods); - class = GetEventClass (eventRef); - if (!NILP (Vmac_emulate_three_button_mouse) && - (class == kEventClassMouse || class == kEventClassCommand)) - { - mods &= ~(optionKey | cmdKey); - } - return mac_to_emacs_modifiers (mods, 0); -} - -/* Given an event ref, return the code to use for the mouse button - code in the emacs input_event. */ -static int -mac_get_mouse_btn (EventRef ref) -{ - EventMouseButton result = kEventMouseButtonPrimary; - GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL, - sizeof (EventMouseButton), NULL, &result); - switch (result) - { - case kEventMouseButtonPrimary: - if (NILP (Vmac_emulate_three_button_mouse)) - return 0; - else { - UInt32 mods = 0; - GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL, - sizeof (UInt32), NULL, &mods); - return mac_get_emulated_btn(mods); - } - case kEventMouseButtonSecondary: - return mac_wheel_button_is_mouse_2 ? 2 : 1; - case kEventMouseButtonTertiary: - case 4: /* 4 is the number for the mouse wheel button */ - return mac_wheel_button_is_mouse_2 ? 1 : 2; - default: - return 0; - } -} - -/* Normally, ConvertEventRefToEventRecord will correctly handle all - events. However the click of the mouse wheel is not converted to a - mouseDown or mouseUp event. Likewise for dead key events. This - calls ConvertEventRefToEventRecord, but then checks to see if it is - a mouse up/down, or a dead key Carbon event that has not been - converted, and if so, converts it by hand (to be picked up in the - XTread_socket loop). */ -static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec) -{ - OSStatus err; - Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec); - EventKind action; - - if (result) - return result; - - switch (GetEventClass (eventRef)) - { - case kEventClassMouse: - switch (GetEventKind (eventRef)) - { - case kEventMouseDown: - eventRec->what = mouseDown; - result = 1; - break; - - case kEventMouseUp: - eventRec->what = mouseUp; - result = 1; - break; - - default: - break; - } - break; - - case kEventClassKeyboard: - switch (GetEventKind (eventRef)) - { - case kEventRawKeyDown: - action = keyDown; - goto keystroke_common; - case kEventRawKeyRepeat: - action = autoKey; - goto keystroke_common; - case kEventRawKeyUp: - action = keyUp; - keystroke_common: - { - unsigned char char_codes; - UInt32 key_code; - - err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes, - typeChar, NULL, sizeof (char), - NULL, &char_codes); - if (err == noErr) - err = GetEventParameter (eventRef, kEventParamKeyCode, - typeUInt32, NULL, sizeof (UInt32), - NULL, &key_code); - if (err == noErr) - { - eventRec->what = action; - eventRec->message = char_codes | ((key_code & 0xff) << 8); - result = 1; - } - } - break; - - default: - break; - } - break; - - default: - break; - } - - if (result) - { - /* Need where and when. */ - UInt32 mods = 0; - - GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint, - NULL, sizeof (Point), NULL, &eventRec->where); - /* Use two step process because new event modifiers are 32-bit - and old are 16-bit. Currently, only loss is NumLock & Fn. */ - GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, - NULL, sizeof (UInt32), NULL, &mods); - eventRec->modifiers = mods; - - eventRec->when = EventTimeToTicks (GetEventTime (eventRef)); - } - - return result; -} - -#endif - -#ifdef MAC_OS8 -static void -do_get_menus (void) -{ - Handle menubar_handle; - MenuRef menu; - - menubar_handle = GetNewMBar (128); - if(menubar_handle == NULL) - abort (); - SetMenuBar (menubar_handle); - DrawMenuBar (); - -#if !TARGET_API_MAC_CARBON - menu = GetMenuRef (M_APPLE); - if (menu != NULL) - AppendResMenu (menu, 'DRVR'); - else - abort (); -#endif -} - - -static void -do_init_managers (void) -{ -#if !TARGET_API_MAC_CARBON - InitGraf (&qd.thePort); - InitFonts (); - FlushEvents (everyEvent, 0); - InitWindows (); - InitMenus (); - TEInit (); - InitDialogs (NULL); -#endif /* !TARGET_API_MAC_CARBON */ - InitCursor (); - -#if !TARGET_API_MAC_CARBON - /* set up some extra stack space for use by emacs */ - SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC)); - - /* MaxApplZone must be called for AppleScript to execute more - complicated scripts */ - MaxApplZone (); - MoreMasters (); -#endif /* !TARGET_API_MAC_CARBON */ -} - -static void -do_check_ram_size (void) -{ - SInt32 physical_ram_size, logical_ram_size; - - if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr - || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr - || physical_ram_size > (1 << VALBITS) - || logical_ram_size > (1 << VALBITS)) - { - StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL); - exit (1); - } -} -#endif /* MAC_OS8 */ - -static void -do_window_update (WindowRef win) -{ - struct frame *f = mac_window_to_frame (win); - - BeginUpdate (win); - - /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED - below. */ - if (win != tip_window) - { - if (f->async_visible == 0) - { - /* Update events may occur when a frame gets iconified. */ -#if 0 - f->async_visible = 1; - f->async_iconified = 0; - SET_FRAME_GARBAGED (f); -#endif - } - else - { - Rect r; -#if TARGET_API_MAC_CARBON - RgnHandle region = NewRgn (); - - GetPortVisibleRegion (GetWindowPort (win), region); - GetRegionBounds (region, &r); - expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top); -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (f); -#endif - UpdateControls (win, region); - DisposeRgn (region); -#else - r = (*win->visRgn)->rgnBBox; - expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top); - UpdateControls (win, win->visRgn); -#endif - } - } - - EndUpdate (win); -} - -static int -is_emacs_window (WindowRef win) -{ - Lisp_Object tail, frame; - - if (!win) - return 0; - - FOR_EACH_FRAME (tail, frame) - if (FRAME_MAC_P (XFRAME (frame))) - if (FRAME_MAC_WINDOW (XFRAME (frame)) == win) - return 1; - - return 0; -} - -#if USE_MAC_TSM -static OSStatus -mac_tsm_resume () -{ - OSStatus err; - ScriptLanguageRecord slrec, *slptr = NULL; - - err = ActivateTSMDocument (tsm_document_id); - - if (err == noErr) - { - if (EQ (Vmac_ts_script_language_on_focus, Qt) - && EQ (saved_ts_script_language_on_focus, Qt)) - slptr = &saved_ts_language; - else if (CONSP (Vmac_ts_script_language_on_focus) - && INTEGERP (XCAR (Vmac_ts_script_language_on_focus)) - && INTEGERP (XCDR (Vmac_ts_script_language_on_focus)) - && CONSP (saved_ts_script_language_on_focus) - && EQ (XCAR (saved_ts_script_language_on_focus), - XCAR (Vmac_ts_script_language_on_focus)) - && EQ (XCDR (saved_ts_script_language_on_focus), - XCDR (Vmac_ts_script_language_on_focus))) - { - slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus)); - slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus)); - slptr = &slrec; - } - } - - if (slptr) - { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 - err = SetDefaultInputMethodOfClass (saved_ts_component, slptr, - kKeyboardInputMethodClass); -#else - err = SetDefaultInputMethod (saved_ts_component, slptr); -#endif - if (err == noErr) - err = SetTextServiceLanguage (slptr); - - /* Seems to be needed on Mac OS X 10.2. */ - if (err == noErr) - KeyScript (slptr->fScript | smKeyForceKeyScriptMask); - } - - return err; -} - -static OSStatus -mac_tsm_suspend () -{ - OSStatus err; - ScriptLanguageRecord slrec, *slptr = NULL; - - saved_ts_script_language_on_focus = Vmac_ts_script_language_on_focus; - - if (EQ (Vmac_ts_script_language_on_focus, Qt)) - { - err = GetTextServiceLanguage (&saved_ts_language); - if (err == noErr) - slptr = &saved_ts_language; - } - else if (CONSP (Vmac_ts_script_language_on_focus) - && INTEGERP (XCAR (Vmac_ts_script_language_on_focus)) - && INTEGERP (XCDR (Vmac_ts_script_language_on_focus))) - { - slrec.fScript = XINT (XCAR (Vmac_ts_script_language_on_focus)); - slrec.fLanguage = XINT (XCDR (Vmac_ts_script_language_on_focus)); - slptr = &slrec; - } - - if (slptr) - { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 - GetDefaultInputMethodOfClass (&saved_ts_component, slptr, - kKeyboardInputMethodClass); -#else - GetDefaultInputMethod (&saved_ts_component, slptr); -#endif - } - - err = DeactivateTSMDocument (tsm_document_id); - - return err; -} -#endif - -#if !TARGET_API_MAC_CARBON -void -do_apple_menu (SInt16 menu_item) -{ - Str255 item_name; - SInt16 da_driver_refnum; - - if (menu_item == I_ABOUT) - NoteAlert (ABOUT_ALERT_ID, NULL); - else - { - GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name); - da_driver_refnum = OpenDeskAcc (item_name); - } -} -#endif /* !TARGET_API_MAC_CARBON */ - -/* Handle drags in size box. Based on code contributed by Ben - Mesander and IM - Window Manager A. */ - -static void -do_grow_window (w, e) - WindowRef w; - const EventRecord *e; -{ - Rect limit_rect; - int rows, columns, width, height; - struct frame *f = mac_window_to_frame (w); - XSizeHints *size_hints = FRAME_SIZE_HINTS (f); - int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE; -#if TARGET_API_MAC_CARBON - Rect new_rect; -#else - long grow_size; -#endif - - if (size_hints->flags & PMinSize) - { - min_width = size_hints->min_width; - min_height = size_hints->min_height; - } - SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE); - -#if TARGET_API_MAC_CARBON - if (!ResizeWindow (w, e->where, &limit_rect, &new_rect)) - return; - height = new_rect.bottom - new_rect.top; - width = new_rect.right - new_rect.left; -#else - grow_size = GrowWindow (w, e->where, &limit_rect); - /* see if it really changed size */ - if (grow_size == 0) - return; - height = HiWord (grow_size); - width = LoWord (grow_size); -#endif - - if (width != FRAME_PIXEL_WIDTH (f) - || height != FRAME_PIXEL_HEIGHT (f)) - { - rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); - columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); - - x_set_window_size (f, 0, columns, rows); - } -} - - -#if TARGET_API_MAC_CARBON -static Point -mac_get_ideal_size (f) - struct frame *f; -{ - struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); - WindowRef w = FRAME_MAC_WINDOW (f); - Point ideal_size; - Rect standard_rect; - int height, width, columns, rows; - - ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS); - ideal_size.v = dpyinfo->height; - IsWindowInStandardState (w, &ideal_size, &standard_rect); - /* Adjust the standard size according to character boundaries. */ - width = standard_rect.right - standard_rect.left; - height = standard_rect.bottom - standard_rect.top; - columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); - rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); - ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns); - ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows); - - return ideal_size; -} -#endif - -/* Handle clicks in zoom box. Calculation of "standard state" based - on code in IM - Window Manager A and code contributed by Ben - Mesander. The standard state of an Emacs window is 80-characters - wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */ - -static void -do_zoom_window (WindowRef w, int zoom_in_or_out) -{ - Rect zoom_rect, port_rect; - int width, height; - struct frame *f = mac_window_to_frame (w); -#if TARGET_API_MAC_CARBON - Point ideal_size = mac_get_ideal_size (f); - - GetWindowBounds (w, kWindowContentRgn, &port_rect); - if (IsWindowInStandardState (w, &ideal_size, &zoom_rect) - && port_rect.left == zoom_rect.left - && port_rect.top == zoom_rect.top) - zoom_in_or_out = inZoomIn; - else - zoom_in_or_out = inZoomOut; - -#ifdef MAC_OS8 - mac_clear_window (f); -#endif - ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size); -#else /* not TARGET_API_MAC_CARBON */ - GrafPtr save_port; - Point top_left; - int w_title_height, rows; - struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); - - GetPort (&save_port); - - SetPortWindowPort (w); - - /* Clear window to avoid flicker. */ - EraseRect (&(w->portRect)); - if (zoom_in_or_out == inZoomOut) - { - SetPt (&top_left, w->portRect.left, w->portRect.top); - LocalToGlobal (&top_left); - - /* calculate height of window's title bar */ - w_title_height = top_left.v - 1 - - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight (); - - /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */ - zoom_rect = qd.screenBits.bounds; - zoom_rect.top += w_title_height; - InsetRect (&zoom_rect, 8, 4); /* not too tight */ - - zoom_rect.right = zoom_rect.left - + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS); - - /* Adjust the standard size according to character boundaries. */ - rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top); - zoom_rect.bottom = - zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows); - - (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState - = zoom_rect; - } - - ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo)); - - SetPort (save_port); -#endif /* not TARGET_API_MAC_CARBON */ - -#if !TARGET_API_MAC_CARBON - /* retrieve window size and update application values */ - port_rect = w->portRect; - height = port_rect.bottom - port_rect.top; - width = port_rect.right - port_rect.left; - - mac_handle_size_change (f, width, height); - mac_handle_origin_change (f); -#endif -} - static void mac_set_unicode_keystroke_event (code, buf) UniChar code; @@ -10435,7 +8471,7 @@ mac_set_unicode_keystroke_event (code, buf) } } -static void +void do_keystroke (action, char_code, key_code, modifiers, timestamp, buf) EventKind action; unsigned char char_code; @@ -10616,7 +8652,7 @@ mac_store_apple_event (class, id, desc) } #if TARGET_API_MAC_CARBON -static OSStatus +OSStatus mac_store_event_ref_as_apple_event (class, id, class_key, id_key, event, num_params, names, types) AEEventClass class; @@ -10652,830 +8688,8 @@ mac_store_event_ref_as_apple_event (class, id, class_key, id_key, return err; } - -void -mac_store_drag_event (window, mouse_pos, modifiers, desc) - WindowRef window; - Point mouse_pos; - SInt16 modifiers; - const AEDesc *desc; -{ - struct input_event buf; - - EVENT_INIT (buf); - - buf.kind = DRAG_N_DROP_EVENT; - buf.modifiers = mac_to_emacs_modifiers (modifiers, 0); - buf.timestamp = TickCount () * (1000 / 60); - XSETINT (buf.x, mouse_pos.h); - XSETINT (buf.y, mouse_pos.v); - XSETFRAME (buf.frame_or_window, mac_window_to_frame (window)); - buf.arg = mac_aedesc_to_lisp (desc); - kbd_buffer_store_event (&buf); -} - -#ifdef MAC_OSX -OSStatus -mac_store_service_event (event) - EventRef event; -{ - OSStatus err; - Lisp_Object id_key; - int num_params; - const EventParamName *names; - const EventParamType *types; - static const EventParamName names_pfm[] = - {kEventParamServiceMessageName, kEventParamServiceUserData}; - static const EventParamType types_pfm[] = - {typeCFStringRef, typeCFStringRef}; - - switch (GetEventKind (event)) - { - case kEventServicePaste: - id_key = Qpaste; - num_params = 0; - names = NULL; - types = NULL; - break; - - case kEventServicePerform: - id_key = Qperform; - num_params = sizeof (names_pfm) / sizeof (names_pfm[0]); - names = names_pfm; - types = types_pfm; - break; - - default: - abort (); - } - - err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key, - event, num_params, - names, types); - - return err; -} -#endif /* MAC_OSX */ - -static pascal OSStatus -mac_handle_window_event (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - WindowRef wp; - OSStatus err, result = eventNotHandledErr; - struct frame *f; - UInt32 attributes; - XSizeHints *size_hints; - - err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef, - NULL, sizeof (WindowRef), NULL, &wp); - if (err != noErr) - return eventNotHandledErr; - - f = mac_window_to_frame (wp); - switch (GetEventKind (event)) - { - /* -- window refresh events -- */ - - case kEventWindowUpdate: - result = CallNextEventHandler (next_handler, event); - if (result != eventNotHandledErr) - break; - - do_window_update (wp); - result = noErr; - break; - - /* -- window state change events -- */ - - case kEventWindowShowing: - size_hints = FRAME_SIZE_HINTS (f); - if (!(size_hints->flags & (USPosition | PPosition))) - { - struct frame *sf = SELECTED_FRAME (); - - if (!(FRAME_MAC_P (sf) && sf->async_visible)) - RepositionWindow (wp, NULL, kWindowCenterOnMainScreen); - else - { - RepositionWindow (wp, FRAME_MAC_WINDOW (sf), -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 - kWindowCascadeStartAtParentWindowScreen -#else - kWindowCascadeOnParentWindowScreen -#endif - ); -#if USE_MAC_TOOLBAR - /* This is a workaround. RepositionWindow fails to put - a window at the cascading position when its parent - window has a Carbon HIToolbar. */ - if ((f->left_pos == sf->left_pos - && f->top_pos == sf->top_pos) - || (f->left_pos == sf->left_pos + 10 * 2 - && f->top_pos == sf->top_pos + 32 * 2)) - MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32); -#endif - } - result = noErr; - } - break; - - case kEventWindowHiding: - /* Before unmapping the window, update the WM_SIZE_HINTS - property to claim that the current position of the window is - user-specified, rather than program-specified, so that when - the window is mapped again, it will be placed at the same - location, without forcing the user to position it by hand - again (they have already done that once for this window.) */ - x_wm_set_size_hint (f, (long) 0, 1); - result = noErr; - break; - - case kEventWindowShown: - case kEventWindowHidden: - case kEventWindowCollapsed: - case kEventWindowExpanded: - mac_handle_visibility_change (f); - result = noErr; - break; - - case kEventWindowBoundsChanging: - result = CallNextEventHandler (next_handler, event); - if (result != eventNotHandledErr) - break; - - err = GetEventParameter (event, kEventParamAttributes, typeUInt32, - NULL, sizeof (UInt32), NULL, &attributes); - if (err != noErr) - break; - - size_hints = FRAME_SIZE_HINTS (f); - if ((attributes & kWindowBoundsChangeUserResize) - && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize)) - == (PResizeInc | PBaseSize | PMinSize))) - { - Rect bounds; - int width, height; - - err = GetEventParameter (event, kEventParamCurrentBounds, - typeQDRectangle, NULL, sizeof (Rect), - NULL, &bounds); - if (err != noErr) - break; - - width = bounds.right - bounds.left; - height = bounds.bottom - bounds.top; - - if (width < size_hints->min_width) - width = size_hints->min_width; - else - width = size_hints->base_width - + (int) ((width - size_hints->base_width) - / (float) size_hints->width_inc + .5) - * size_hints->width_inc; - - if (height < size_hints->min_height) - height = size_hints->min_height; - else - height = size_hints->base_height - + (int) ((height - size_hints->base_height) - / (float) size_hints->height_inc + .5) - * size_hints->height_inc; - - bounds.right = bounds.left + width; - bounds.bottom = bounds.top + height; - SetEventParameter (event, kEventParamCurrentBounds, - typeQDRectangle, sizeof (Rect), &bounds); - result = noErr; - } - break; - - case kEventWindowBoundsChanged: - err = GetEventParameter (event, kEventParamAttributes, typeUInt32, - NULL, sizeof (UInt32), NULL, &attributes); - if (err != noErr) - break; - - if (attributes & kWindowBoundsChangeSizeChanged) - { - Rect bounds; - - err = GetEventParameter (event, kEventParamCurrentBounds, - typeQDRectangle, NULL, sizeof (Rect), - NULL, &bounds); - if (err == noErr) - { - int width, height; - - width = bounds.right - bounds.left; - height = bounds.bottom - bounds.top; - mac_handle_size_change (f, width, height); - mac_wakeup_from_rne (); - } - } - - if (attributes & kWindowBoundsChangeOriginChanged) - mac_handle_origin_change (f); - - result = noErr; - break; - - /* -- window action events -- */ - - case kEventWindowClose: - { - struct input_event buf; - - EVENT_INIT (buf); - buf.kind = DELETE_WINDOW_EVENT; - XSETFRAME (buf.frame_or_window, f); - buf.arg = Qnil; - kbd_buffer_store_event (&buf); - } - result = noErr; - break; - - case kEventWindowGetIdealSize: - result = CallNextEventHandler (next_handler, event); - if (result != eventNotHandledErr) - break; - - { - Point ideal_size = mac_get_ideal_size (f); - - err = SetEventParameter (event, kEventParamDimensions, - typeQDPoint, sizeof (Point), &ideal_size); - if (err == noErr) - result = noErr; - } - break; - -#ifdef MAC_OSX - case kEventWindowToolbarSwitchMode: - { - static const EventParamName names[] = {kEventParamDirectObject, - kEventParamWindowMouseLocation, - kEventParamKeyModifiers, - kEventParamMouseButton, - kEventParamClickCount, - kEventParamMouseChord}; - static const EventParamType types[] = {typeWindowRef, - typeQDPoint, - typeUInt32, - typeMouseButton, - typeUInt32, - typeUInt32}; - int num_params = sizeof (names) / sizeof (names[0]); - - err = mac_store_event_ref_as_apple_event (0, 0, - Qwindow, - Qtoolbar_switch_mode, - event, num_params, - names, types); - } - if (err == noErr) - result = noErr; - break; -#endif - -#if USE_MAC_TSM - /* -- window focus events -- */ - - case kEventWindowFocusAcquired: - err = mac_tsm_resume (); - if (err == noErr) - result = noErr; - break; - - case kEventWindowFocusRelinquish: - err = mac_tsm_suspend (); - if (err == noErr) - result = noErr; - break; -#endif - - default: - abort (); - } - - return result; -} - -static pascal OSStatus -mac_handle_keyboard_event (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - OSStatus err, result = eventNotHandledErr; - UInt32 event_kind, key_code, modifiers; - unsigned char char_code; - - event_kind = GetEventKind (event); - switch (event_kind) - { - case kEventRawKeyDown: - case kEventRawKeyRepeat: - case kEventRawKeyUp: - /* When using Carbon Events, we need to pass raw keyboard events - to the TSM ourselves. If TSM handles it, it will pass back - noErr, otherwise it will pass back "eventNotHandledErr" and - we can process it normally. */ - result = CallNextEventHandler (next_handler, event); - if (result != eventNotHandledErr) - break; - - if (read_socket_inev == NULL) - break; - -#if USE_MAC_TSM - if (read_socket_inev->kind != NO_EVENT) - { - result = noErr; - break; - } -#endif - - if (event_kind == kEventRawKeyUp) - break; - - err = GetEventParameter (event, kEventParamKeyMacCharCodes, - typeChar, NULL, - sizeof (char), NULL, &char_code); - if (err != noErr) - break; - - err = GetEventParameter (event, kEventParamKeyCode, - typeUInt32, NULL, - sizeof (UInt32), NULL, &key_code); - if (err != noErr) - break; - - err = GetEventParameter (event, kEventParamKeyModifiers, - typeUInt32, NULL, - sizeof (UInt32), NULL, &modifiers); - if (err != noErr) - break; - - do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey), - char_code, key_code, modifiers, - ((unsigned long) - (GetEventTime (event) / kEventDurationMillisecond)), - read_socket_inev); - result = noErr; - break; - - default: - abort (); - } - - return result; -} - -static pascal OSStatus -mac_handle_command_event (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - OSStatus err, result = eventNotHandledErr; - HICommand command; - static const EventParamName names[] = - {kEventParamDirectObject, kEventParamKeyModifiers}; - static const EventParamType types[] = - {typeHICommand, typeUInt32}; - int num_params = sizeof (names) / sizeof (names[0]); - - err = GetEventParameter (event, kEventParamDirectObject, typeHICommand, - NULL, sizeof (HICommand), NULL, &command); - if (err != noErr) - return eventNotHandledErr; - - switch (GetEventKind (event)) - { - case kEventCommandProcess: - result = CallNextEventHandler (next_handler, event); - if (result != eventNotHandledErr) - break; - - err = GetEventParameter (event, kEventParamDirectObject, - typeHICommand, NULL, - sizeof (HICommand), NULL, &command); - - if (err != noErr || command.commandID == 0) - break; - - /* A HI command event is mapped to an Apple event whose event - class symbol is `hi-command' and event ID is its command - ID. */ - err = mac_store_event_ref_as_apple_event (0, command.commandID, - Qhi_command, Qnil, - event, num_params, - names, types); - if (err == noErr) - result = noErr; - break; - - default: - abort (); - } - - return result; -} - -static pascal OSStatus -mac_handle_mouse_event (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - OSStatus err, result = eventNotHandledErr; - - switch (GetEventKind (event)) - { - case kEventMouseWheelMoved: - { - WindowRef wp; - struct frame *f; - EventMouseWheelAxis axis; - SInt32 delta; - Point point; - - result = CallNextEventHandler (next_handler, event); - if (result != eventNotHandledErr || read_socket_inev == NULL) - break; - - f = mac_focus_frame (&one_mac_display_info); - - err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef, - NULL, sizeof (WindowRef), NULL, &wp); - if (err != noErr - || wp != FRAME_MAC_WINDOW (f)) - break; - - err = GetEventParameter (event, kEventParamMouseWheelAxis, - typeMouseWheelAxis, NULL, - sizeof (EventMouseWheelAxis), NULL, &axis); - if (err != noErr || axis != kEventMouseWheelAxisY) - break; - - err = GetEventParameter (event, kEventParamMouseLocation, - typeQDPoint, NULL, sizeof (Point), - NULL, &point); - if (err != noErr) - break; - - point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); - point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); - if (point.h < 0 || point.v < 0 - || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1), - f->tool_bar_window)) - break; - - err = GetEventParameter (event, kEventParamMouseWheelDelta, - typeSInt32, NULL, sizeof (SInt32), - NULL, &delta); - if (err != noErr) - break; - - read_socket_inev->kind = WHEEL_EVENT; - read_socket_inev->code = 0; - read_socket_inev->modifiers = - (mac_event_to_emacs_modifiers (event) - | ((delta < 0) ? down_modifier : up_modifier)); - XSETINT (read_socket_inev->x, point.h); - XSETINT (read_socket_inev->y, point.v); - XSETFRAME (read_socket_inev->frame_or_window, f); - - result = noErr; - } - break; - - default: - abort (); - } - - return result; -} - -#if USE_MAC_TSM -static pascal OSStatus -mac_handle_text_input_event (next_handler, event, data) - EventHandlerCallRef next_handler; - EventRef event; - void *data; -{ - OSStatus err, result; - Lisp_Object id_key = Qnil; - int num_params; - const EventParamName *names; - const EventParamType *types; - static UInt32 seqno_uaia = 0; - static const EventParamName names_uaia[] = - {kEventParamTextInputSendComponentInstance, - kEventParamTextInputSendRefCon, - kEventParamTextInputSendSLRec, - kEventParamTextInputSendFixLen, - kEventParamTextInputSendText, - kEventParamTextInputSendUpdateRng, - kEventParamTextInputSendHiliteRng, - kEventParamTextInputSendClauseRng, - kEventParamTextInputSendPinRng, - kEventParamTextInputSendTextServiceEncoding, - kEventParamTextInputSendTextServiceMacEncoding, - EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER}; - static const EventParamType types_uaia[] = - {typeComponentInstance, - typeLongInteger, - typeIntlWritingCode, - typeLongInteger, -#ifdef MAC_OSX - typeUnicodeText, -#else - typeChar, -#endif - typeTextRangeArray, - typeTextRangeArray, - typeOffsetArray, - typeTextRange, - typeUInt32, - typeUInt32, - typeUInt32}; - static const EventParamName names_ufke[] = - {kEventParamTextInputSendComponentInstance, - kEventParamTextInputSendRefCon, - kEventParamTextInputSendSLRec, - kEventParamTextInputSendText}; - static const EventParamType types_ufke[] = - {typeComponentInstance, - typeLongInteger, - typeIntlWritingCode, - typeUnicodeText}; - - result = CallNextEventHandler (next_handler, event); - if (result != eventNotHandledErr) - return result; - - switch (GetEventKind (event)) - { - case kEventTextInputUpdateActiveInputArea: - id_key = Qupdate_active_input_area; - num_params = sizeof (names_uaia) / sizeof (names_uaia[0]); - names = names_uaia; - types = types_uaia; - SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER, - typeUInt32, sizeof (UInt32), &seqno_uaia); - seqno_uaia++; - result = noErr; - break; - - case kEventTextInputUnicodeForKeyEvent: - { - EventRef kbd_event; - UInt32 actual_size, modifiers, key_code; - - err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent, - typeEventRef, NULL, sizeof (EventRef), NULL, - &kbd_event); - if (err == noErr) - err = GetEventParameter (kbd_event, kEventParamKeyModifiers, - typeUInt32, NULL, - sizeof (UInt32), NULL, &modifiers); - if (err == noErr) - err = GetEventParameter (kbd_event, kEventParamKeyCode, - typeUInt32, NULL, sizeof (UInt32), - NULL, &key_code); - if (err == noErr && mac_mapped_modifiers (modifiers, key_code)) - /* There're mapped modifier keys. Process it in - do_keystroke. */ - break; - if (err == noErr) - err = GetEventParameter (kbd_event, kEventParamKeyUnicodes, - typeUnicodeText, NULL, 0, &actual_size, - NULL); - if (err == noErr && actual_size == sizeof (UniChar)) - { - UniChar code; - - err = GetEventParameter (kbd_event, kEventParamKeyUnicodes, - typeUnicodeText, NULL, - sizeof (UniChar), NULL, &code); - if (err == noErr && code < 0x80) - { - /* ASCII character. Process it in do_keystroke. */ - if (read_socket_inev && code >= 0x20 && code <= 0x7e - && !(key_code <= 0x7f - && keycode_to_xkeysym_table [key_code])) - { - struct frame *f = mac_focus_frame (&one_mac_display_info); - - read_socket_inev->kind = ASCII_KEYSTROKE_EVENT; - read_socket_inev->code = code; - read_socket_inev->modifiers = - mac_to_emacs_modifiers (modifiers, 0); - read_socket_inev->modifiers |= - (extra_keyboard_modifiers - & (meta_modifier | alt_modifier - | hyper_modifier | super_modifier)); - XSETFRAME (read_socket_inev->frame_or_window, f); - } - break; - } - } - if (err == noErr) - { - /* Non-ASCII keystrokes without mapped modifiers are - processed at the Lisp level. */ - id_key = Qunicode_for_key_event; - num_params = sizeof (names_ufke) / sizeof (names_ufke[0]); - names = names_ufke; - types = types_ufke; - result = noErr; - } - } - break; - - case kEventTextInputOffsetToPos: - { - struct frame *f; - struct window *w; - Point p; - - if (!OVERLAYP (Vmac_ts_active_input_overlay)) - break; - - /* Strictly speaking, this is not always correct because - previous events may change some states about display. */ - if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string))) - { - /* Active input area is displayed around the current point. */ - f = SELECTED_FRAME (); - w = XWINDOW (f->selected_window); - } - else if (WINDOWP (echo_area_window)) - { - /* Active input area is displayed in the echo area. */ - w = XWINDOW (echo_area_window); - f = WINDOW_XFRAME (w); - } - else - break; - - p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x) - + WINDOW_LEFT_FRINGE_WIDTH (w) - + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f)); - p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y) - + FONT_BASE (FRAME_FONT (f)) - + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f)); - err = SetEventParameter (event, kEventParamTextInputReplyPoint, - typeQDPoint, sizeof (typeQDPoint), &p); - if (err == noErr) - result = noErr; - } - break; - - default: - abort (); - } - - if (!NILP (id_key)) - err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key, - event, num_params, - names, types); - return result; -} -#endif #endif /* TARGET_API_MAC_CARBON */ - -OSStatus -install_window_handler (window) - WindowRef window; -{ - OSStatus err = noErr; - -#if TARGET_API_MAC_CARBON - if (err == noErr) - { - static const EventTypeSpec specs[] = - { - /* -- window refresh events -- */ - {kEventClassWindow, kEventWindowUpdate}, - /* -- window state change events -- */ - {kEventClassWindow, kEventWindowShowing}, - {kEventClassWindow, kEventWindowHiding}, - {kEventClassWindow, kEventWindowShown}, - {kEventClassWindow, kEventWindowHidden}, - {kEventClassWindow, kEventWindowCollapsed}, - {kEventClassWindow, kEventWindowExpanded}, - {kEventClassWindow, kEventWindowBoundsChanging}, - {kEventClassWindow, kEventWindowBoundsChanged}, - /* -- window action events -- */ - {kEventClassWindow, kEventWindowClose}, - {kEventClassWindow, kEventWindowGetIdealSize}, -#ifdef MAC_OSX - {kEventClassWindow, kEventWindowToolbarSwitchMode}, -#endif -#if USE_MAC_TSM - /* -- window focus events -- */ - {kEventClassWindow, kEventWindowFocusAcquired}, - {kEventClassWindow, kEventWindowFocusRelinquish}, -#endif - }; - static EventHandlerUPP handle_window_eventUPP = NULL; - - if (handle_window_eventUPP == NULL) - handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event); - - err = InstallWindowEventHandler (window, handle_window_eventUPP, - GetEventTypeCount (specs), - specs, NULL, NULL); - } -#endif - - if (err == noErr) - err = install_drag_handler (window); - - return err; -} - -void -remove_window_handler (window) - WindowRef window; -{ - remove_drag_handler (window); -} - -#if TARGET_API_MAC_CARBON -static OSStatus -install_application_handler () -{ - OSStatus err = noErr; - - if (err == noErr) - { - static const EventTypeSpec specs[] = - {{kEventClassKeyboard, kEventRawKeyDown}, - {kEventClassKeyboard, kEventRawKeyRepeat}, - {kEventClassKeyboard, kEventRawKeyUp}}; - - err = InstallApplicationEventHandler (NewEventHandlerUPP - (mac_handle_keyboard_event), - GetEventTypeCount (specs), - specs, NULL, NULL); - } - - if (err == noErr) - { - static const EventTypeSpec specs[] = - {{kEventClassCommand, kEventCommandProcess}}; - - err = InstallApplicationEventHandler (NewEventHandlerUPP - (mac_handle_command_event), - GetEventTypeCount (specs), - specs, NULL, NULL); - } - - if (err == noErr) - { - static const EventTypeSpec specs[] = - {{kEventClassMouse, kEventMouseWheelMoved}}; - - err = InstallApplicationEventHandler (NewEventHandlerUPP - (mac_handle_mouse_event), - GetEventTypeCount (specs), - specs, NULL, NULL); - } - -#if USE_MAC_TSM - if (err == noErr) - { - static const EventTypeSpec spec[] = - {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea}, - {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent}, - {kEventClassTextInput, kEventTextInputOffsetToPos}}; - - err = InstallApplicationEventHandler (NewEventHandlerUPP - (mac_handle_text_input_event), - GetEventTypeCount (spec), - spec, NULL, NULL); - } -#endif - - if (err == noErr) - err = install_menu_target_item_handler (); - -#ifdef MAC_OSX - if (err == noErr) - err = install_service_handler (); -#endif - - return err; -} -#endif - static pascal void mac_handle_dm_notification (event) AppleEvent *event; @@ -11529,7 +8743,7 @@ init_dm_notification_handler () return err; } -static void +void mac_get_screen_info (dpyinfo) struct mac_display_info *dpyinfo; { @@ -11584,6 +8798,78 @@ mac_get_screen_info (dpyinfo) #endif /* !MAC_OSX */ } + +/*********************************************************************** + Initialization (Mac OS Classic) + ***********************************************************************/ + +#ifdef MAC_OS8 +extern void init_emacs_passwd_dir (); +extern int emacs_main (int, char **, char **); + +extern void initialize_applescript(); +extern void terminate_applescript(); + +static void +do_get_menus (void) +{ + Handle menubar_handle; + MenuRef menu; + + menubar_handle = GetNewMBar (128); + if(menubar_handle == NULL) + abort (); + SetMenuBar (menubar_handle); + DrawMenuBar (); + +#if !TARGET_API_MAC_CARBON + menu = GetMenuRef (M_APPLE); + if (menu != NULL) + AppendResMenu (menu, 'DRVR'); + else + abort (); +#endif +} + +static void +do_init_managers (void) +{ +#if !TARGET_API_MAC_CARBON + InitGraf (&qd.thePort); + InitFonts (); + FlushEvents (everyEvent, 0); + InitWindows (); + InitMenus (); + TEInit (); + InitDialogs (NULL); +#endif /* !TARGET_API_MAC_CARBON */ + InitCursor (); + +#if !TARGET_API_MAC_CARBON + /* set up some extra stack space for use by emacs */ + SetApplLimit ((Ptr) ((long) GetApplLimit () - EXTRA_STACK_ALLOC)); + + /* MaxApplZone must be called for AppleScript to execute more + complicated scripts */ + MaxApplZone (); + MoreMasters (); +#endif /* !TARGET_API_MAC_CARBON */ +} + +static void +do_check_ram_size (void) +{ + SInt32 physical_ram_size, logical_ram_size; + + if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr + || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr + || physical_ram_size > (1 << VALBITS) + || logical_ram_size > (1 << VALBITS)) + { + StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL); + exit (1); + } +} #if __profile__ void @@ -11608,7 +8894,6 @@ profiler_exit_proc () (defined further below) to read input. This is where WaitNextEvent/ReceiveNextEvent is called to process Mac events. */ -#ifdef MAC_OS8 #undef main int main (void) @@ -11667,755 +8952,6 @@ main (void) /* Never reached - real exit in Fkill_emacs */ return 0; } -#endif - -#if !TARGET_API_MAC_CARBON -static RgnHandle mouse_region = NULL; - -Boolean -mac_wait_next_event (er, sleep_time, dequeue) - EventRecord *er; - UInt32 sleep_time; - Boolean dequeue; -{ - static EventRecord er_buf = {nullEvent}; - UInt32 target_tick, current_tick; - EventMask event_mask; - - if (mouse_region == NULL) - mouse_region = NewRgn (); - - event_mask = everyEvent; - if (!mac_ready_for_apple_events) - event_mask -= highLevelEventMask; - - current_tick = TickCount (); - target_tick = current_tick + sleep_time; - - if (er_buf.what == nullEvent) - while (!WaitNextEvent (event_mask, &er_buf, - target_tick - current_tick, mouse_region)) - { - current_tick = TickCount (); - if (target_tick <= current_tick) - return false; - } - - *er = er_buf; - if (dequeue) - er_buf.what = nullEvent; - return true; -} -#endif /* not TARGET_API_MAC_CARBON */ - -#if TARGET_API_MAC_CARBON -OSStatus -mac_post_mouse_moved_event () -{ - EventRef event = NULL; - OSStatus err; - - err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0, - kEventAttributeNone, &event); - if (err == noErr) - { - Point mouse_pos; - - GetGlobalMouse (&mouse_pos); - err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint, - sizeof (Point), &mouse_pos); - } - if (err == noErr) - { - UInt32 modifiers = GetCurrentKeyModifiers (); - - err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32, - sizeof (UInt32), &modifiers); - } - if (err == noErr) - err = PostEventToQueue (GetCurrentEventQueue (), event, - kEventPriorityStandard); - if (event) - ReleaseEvent (event); - - return err; -} -#endif - -/* Emacs calls this whenever it wants to read an input event from the - user. */ -int -XTread_socket (sd, expected, hold_quit) - int sd, expected; - struct input_event *hold_quit; -{ - struct input_event inev; - int count = 0; -#if TARGET_API_MAC_CARBON - EventRef eventRef; - EventTargetRef toolbox_dispatcher; -#endif - EventRecord er; - struct mac_display_info *dpyinfo = &one_mac_display_info; - - if (interrupt_input_blocked) - { - interrupt_input_pending = 1; - return -1; - } - - interrupt_input_pending = 0; - BLOCK_INPUT; - - /* So people can tell when we have read the available input. */ - input_signal_count++; - - ++handling_signal; - -#if TARGET_API_MAC_CARBON - toolbox_dispatcher = GetEventDispatcherTarget (); - - while ( -#if USE_CG_DRAWING - mac_prepare_for_quickdraw (NULL), -#endif - !ReceiveNextEvent (0, NULL, kEventDurationNoWait, - kEventRemoveFromQueue, &eventRef)) -#else /* !TARGET_API_MAC_CARBON */ - while (mac_wait_next_event (&er, 0, true)) -#endif /* !TARGET_API_MAC_CARBON */ - { - int do_help = 0; - struct frame *f; - unsigned long timestamp; - - EVENT_INIT (inev); - inev.kind = NO_EVENT; - inev.arg = Qnil; - -#if TARGET_API_MAC_CARBON - timestamp = GetEventTime (eventRef) / kEventDurationMillisecond; - - if (!mac_convert_event_ref (eventRef, &er)) - goto OTHER; -#else /* !TARGET_API_MAC_CARBON */ - timestamp = er.when * (1000 / 60); /* ticks to milliseconds */ -#endif /* !TARGET_API_MAC_CARBON */ - - switch (er.what) - { - case mouseDown: - case mouseUp: - { - WindowRef window_ptr; - ControlPartCode part_code; - int tool_bar_p = 0; - -#if TARGET_API_MAC_CARBON - OSStatus err; - - /* This is needed to send mouse events like aqua window - buttons to the correct handler. */ - read_socket_inev = &inev; - err = SendEventToEventTarget (eventRef, toolbox_dispatcher); - read_socket_inev = NULL; - if (err != eventNotHandledErr) - break; -#endif - last_mouse_glyph_frame = 0; - - if (dpyinfo->grabbed && last_mouse_frame - && FRAME_LIVE_P (last_mouse_frame)) - { - window_ptr = FRAME_MAC_WINDOW (last_mouse_frame); - part_code = inContent; - } - else - { - part_code = FindWindow (er.where, &window_ptr); - if (tip_window && window_ptr == tip_window) - { - HideWindow (tip_window); - part_code = FindWindow (er.where, &window_ptr); - } - } - - if (er.what != mouseDown && - (part_code != inContent || dpyinfo->grabbed == 0)) - break; - - switch (part_code) - { - case inMenuBar: - f = mac_focus_frame (dpyinfo); - saved_menu_event_location = er.where; - inev.kind = MENU_BAR_ACTIVATE_EVENT; - XSETFRAME (inev.frame_or_window, f); - break; - - case inContent: - if ( -#if TARGET_API_MAC_CARBON - FrontNonFloatingWindow () -#else - FrontWindow () -#endif - != window_ptr - || (mac_window_to_frame (window_ptr) - != dpyinfo->x_focus_frame)) - SelectWindow (window_ptr); - else - { - ControlPartCode control_part_code; - ControlRef ch; - Point mouse_loc; -#ifdef MAC_OSX - ControlKind control_kind; -#endif - - f = mac_window_to_frame (window_ptr); - /* convert to local coordinates of new window */ - mouse_loc.h = (er.where.h - - (f->left_pos - + FRAME_OUTER_TO_INNER_DIFF_X (f))); - mouse_loc.v = (er.where.v - - (f->top_pos - + FRAME_OUTER_TO_INNER_DIFF_Y (f))); -#if TARGET_API_MAC_CARBON - ch = FindControlUnderMouse (mouse_loc, window_ptr, - &control_part_code); -#ifdef MAC_OSX - if (ch) - GetControlKind (ch, &control_kind); -#endif -#else - control_part_code = FindControl (mouse_loc, window_ptr, - &ch); -#endif - -#if TARGET_API_MAC_CARBON - inev.code = mac_get_mouse_btn (eventRef); - inev.modifiers = mac_event_to_emacs_modifiers (eventRef); -#else - inev.code = mac_get_emulated_btn (er.modifiers); - inev.modifiers = mac_to_emacs_modifiers (er.modifiers, 0); -#endif - XSETINT (inev.x, mouse_loc.h); - XSETINT (inev.y, mouse_loc.v); - - if ((dpyinfo->grabbed && tracked_scroll_bar) - || (ch != 0 -#ifndef USE_TOOLKIT_SCROLL_BARS - /* control_part_code becomes kControlNoPart if - a progress indicator is clicked. */ - && control_part_code != kControlNoPart -#else /* USE_TOOLKIT_SCROLL_BARS */ -#ifdef MAC_OSX - && control_kind.kind == kControlKindScrollBar -#endif /* MAC_OSX */ -#endif /* USE_TOOLKIT_SCROLL_BARS */ - )) - { - struct scroll_bar *bar; - - if (dpyinfo->grabbed && tracked_scroll_bar) - { - bar = tracked_scroll_bar; -#ifndef USE_TOOLKIT_SCROLL_BARS - control_part_code = kControlIndicatorPart; -#endif - } - else - bar = (struct scroll_bar *) GetControlReference (ch); -#ifdef USE_TOOLKIT_SCROLL_BARS - /* Make the "Ctrl-Mouse-2 splits window" work - for toolkit scroll bars. */ - if (inev.modifiers & ctrl_modifier) - x_scroll_bar_handle_click (bar, control_part_code, - &er, &inev); - else if (er.what == mouseDown) - x_scroll_bar_handle_press (bar, control_part_code, - mouse_loc, &inev); - else - x_scroll_bar_handle_release (bar, &inev); -#else /* not USE_TOOLKIT_SCROLL_BARS */ - x_scroll_bar_handle_click (bar, control_part_code, - &er, &inev); - if (er.what == mouseDown - && control_part_code == kControlIndicatorPart) - tracked_scroll_bar = bar; - else - tracked_scroll_bar = NULL; -#endif /* not USE_TOOLKIT_SCROLL_BARS */ - } - else - { - Lisp_Object window; - int x = mouse_loc.h; - int y = mouse_loc.v; - - window = window_from_coordinates (f, x, y, 0, 0, 0, 1); - if (EQ (window, f->tool_bar_window)) - { - if (er.what == mouseDown) - handle_tool_bar_click (f, x, y, 1, 0); - else - handle_tool_bar_click (f, x, y, 0, - inev.modifiers); - tool_bar_p = 1; - } - else - { - XSETFRAME (inev.frame_or_window, f); - inev.kind = MOUSE_CLICK_EVENT; - } - } - - if (er.what == mouseDown) - { - dpyinfo->grabbed |= (1 << inev.code); - last_mouse_frame = f; - - if (!tool_bar_p) - last_tool_bar_item = -1; - } - else - { - if ((dpyinfo->grabbed & (1 << inev.code)) == 0) - /* If a button is released though it was not - previously pressed, that would be because - of multi-button emulation. */ - dpyinfo->grabbed = 0; - else - dpyinfo->grabbed &= ~(1 << inev.code); - } - - /* Ignore any mouse motion that happened before - this event; any subsequent mouse-movement Emacs - events should reflect only motion after the - ButtonPress. */ - if (f != 0) - f->mouse_moved = 0; - -#ifdef USE_TOOLKIT_SCROLL_BARS - if (inev.kind == MOUSE_CLICK_EVENT - || (inev.kind == SCROLL_BAR_CLICK_EVENT - && (inev.modifiers & ctrl_modifier))) -#endif - switch (er.what) - { - case mouseDown: - inev.modifiers |= down_modifier; - break; - case mouseUp: - inev.modifiers |= up_modifier; - break; - } - } - break; - - case inDrag: -#if TARGET_API_MAC_CARBON - case inProxyIcon: - if (IsWindowPathSelectClick (window_ptr, &er)) - { - WindowPathSelect (window_ptr, NULL, NULL); - break; - } - if (part_code == inProxyIcon - && (TrackWindowProxyDrag (window_ptr, er.where) - != errUserWantsToDragWindow)) - break; - DragWindow (window_ptr, er.where, NULL); -#else /* not TARGET_API_MAC_CARBON */ - DragWindow (window_ptr, er.where, &qd.screenBits.bounds); - /* Update the frame parameters. */ - { - struct frame *f = mac_window_to_frame (window_ptr); - - if (f && !f->async_iconified) - mac_handle_origin_change (f); - } -#endif /* not TARGET_API_MAC_CARBON */ - break; - - case inGoAway: - if (TrackGoAway (window_ptr, er.where)) - { - inev.kind = DELETE_WINDOW_EVENT; - XSETFRAME (inev.frame_or_window, - mac_window_to_frame (window_ptr)); - } - break; - - /* window resize handling added --ben */ - case inGrow: - do_grow_window (window_ptr, &er); - break; - - /* window zoom handling added --ben */ - case inZoomIn: - case inZoomOut: - if (TrackBox (window_ptr, er.where, part_code)) - do_zoom_window (window_ptr, part_code); - break; - -#if USE_MAC_TOOLBAR - case inStructure: - { - OSStatus err; - HIViewRef ch; - - err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr), - eventRef, &ch); - /* This doesn't work on Mac OS X 10.2. */ - if (err == noErr) - HIViewClick (ch, eventRef); - } - break; -#endif /* USE_MAC_TOOLBAR */ - - default: - break; - } - } - break; - -#if !TARGET_API_MAC_CARBON - case updateEvt: - do_window_update ((WindowRef) er.message); - break; -#endif - - case osEvt: -#if TARGET_API_MAC_CARBON - if (SendEventToEventTarget (eventRef, toolbox_dispatcher) - != eventNotHandledErr) - break; -#endif - switch ((er.message >> 24) & 0x000000FF) - { -#if USE_MAC_TSM - case suspendResumeMessage: - if (er.message & resumeFlag) - mac_tsm_resume (); - else - mac_tsm_suspend (); - break; -#endif - - case mouseMovedMessage: -#if !TARGET_API_MAC_CARBON - SetRectRgn (mouse_region, er.where.h, er.where.v, - er.where.h + 1, er.where.v + 1); -#endif - previous_help_echo_string = help_echo_string; - help_echo_string = Qnil; - - if (dpyinfo->grabbed && last_mouse_frame - && FRAME_LIVE_P (last_mouse_frame)) - f = last_mouse_frame; - else - f = dpyinfo->x_focus_frame; - - if (dpyinfo->mouse_face_hidden) - { - dpyinfo->mouse_face_hidden = 0; - clear_mouse_face (dpyinfo); - } - - if (f) - { - WindowRef wp = FRAME_MAC_WINDOW (f); - Point mouse_pos; - - mouse_pos.h = (er.where.h - - (f->left_pos - + FRAME_OUTER_TO_INNER_DIFF_X (f))); - mouse_pos.v = (er.where.v - - (f->top_pos - + FRAME_OUTER_TO_INNER_DIFF_Y (f))); - if (dpyinfo->grabbed && tracked_scroll_bar) -#ifdef USE_TOOLKIT_SCROLL_BARS - x_scroll_bar_handle_drag (wp, tracked_scroll_bar, - mouse_pos, &inev); -#else /* not USE_TOOLKIT_SCROLL_BARS */ - x_scroll_bar_note_movement (tracked_scroll_bar, - mouse_pos.v - - XINT (tracked_scroll_bar->top), - er.when * (1000 / 60)); -#endif /* not USE_TOOLKIT_SCROLL_BARS */ - else - { - /* Generate SELECT_WINDOW_EVENTs when needed. */ - if (!NILP (Vmouse_autoselect_window)) - { - Lisp_Object window; - - window = window_from_coordinates (f, - mouse_pos.h, - mouse_pos.v, - 0, 0, 0, 0); - - /* Window will be selected only when it is - not selected now and last mouse movement - event was not in it. Minibuffer window - will be selected only when it is active. */ - if (WINDOWP (window) - && !EQ (window, last_window) - && !EQ (window, selected_window) - /* For click-to-focus window managers - create event iff we don't leave the - selected frame. */ - && (focus_follows_mouse - || (EQ (XWINDOW (window)->frame, - XWINDOW (selected_window)->frame)))) - { - inev.kind = SELECT_WINDOW_EVENT; - inev.frame_or_window = window; - } - - last_window=window; - } - if (!note_mouse_movement (f, &mouse_pos)) - help_echo_string = previous_help_echo_string; -#if USE_MAC_TOOLBAR - else - mac_tool_bar_note_mouse_movement (f, eventRef); -#endif - } - } - - /* If the contents of the global variable - help_echo_string has changed, generate a - HELP_EVENT. */ - if (!NILP (help_echo_string) || !NILP (previous_help_echo_string)) - do_help = 1; - break; - } - break; - - case activateEvt: - { - WindowRef window_ptr = (WindowRef) er.message; - OSErr err; - ControlRef root_control; - - if (window_ptr == tip_window) - { - HideWindow (tip_window); - break; - } - - if (!is_emacs_window (window_ptr)) - goto OTHER; - - f = mac_window_to_frame (window_ptr); - - if ((er.modifiers & activeFlag) != 0) - { - /* A window has been activated */ - Point mouse_loc; - - err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control); - if (err == noErr) - ActivateControl (root_control); - - x_detect_focus_change (dpyinfo, &er, &inev); - - mouse_loc.h = (er.where.h - - (f->left_pos - + FRAME_OUTER_TO_INNER_DIFF_X (f))); - mouse_loc.v = (er.where.v - - (f->top_pos - + FRAME_OUTER_TO_INNER_DIFF_Y (f))); - /* Window-activated event counts as mouse movement, - so update things that depend on mouse position. */ - note_mouse_movement (f, &mouse_loc); - } - else - { - /* A window has been deactivated */ - err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control); - if (err == noErr) - DeactivateControl (root_control); - -#ifdef USE_TOOLKIT_SCROLL_BARS - if (dpyinfo->grabbed && tracked_scroll_bar) - { - struct input_event event; - - EVENT_INIT (event); - event.kind = NO_EVENT; - x_scroll_bar_handle_release (tracked_scroll_bar, &event); - if (event.kind != NO_EVENT) - { - event.timestamp = timestamp; - kbd_buffer_store_event_hold (&event, hold_quit); - count++; - } - } -#endif - dpyinfo->grabbed = 0; - - x_detect_focus_change (dpyinfo, &er, &inev); - - if (f == dpyinfo->mouse_face_mouse_frame) - { - /* If we move outside the frame, then we're - certainly no longer on any text in the - frame. */ - clear_mouse_face (dpyinfo); - dpyinfo->mouse_face_mouse_frame = 0; - } - - /* Generate a nil HELP_EVENT to cancel a help-echo. - Do it only if there's something to cancel. - Otherwise, the startup message is cleared when the - mouse leaves the frame. */ - if (any_help_event_p) - do_help = -1; - } - } - break; - - case keyDown: - case keyUp: - case autoKey: - ObscureCursor (); - - f = mac_focus_frame (dpyinfo); - XSETFRAME (inev.frame_or_window, f); - - /* If mouse-highlight is an integer, input clears out mouse - highlighting. */ - if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight) - && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window)) - { - clear_mouse_face (dpyinfo); - dpyinfo->mouse_face_hidden = 1; - } - - { - UInt32 modifiers = er.modifiers, mapped_modifiers; - UInt32 key_code = (er.message & keyCodeMask) >> 8; - -#ifdef MAC_OSX - GetEventParameter (eventRef, kEventParamKeyModifiers, - typeUInt32, NULL, - sizeof (UInt32), NULL, &modifiers); -#endif - mapped_modifiers = mac_mapped_modifiers (modifiers, key_code); - -#if TARGET_API_MAC_CARBON - if (!(mapped_modifiers - & ~(mac_pass_command_to_system ? cmdKey : 0) - & ~(mac_pass_control_to_system ? controlKey : 0))) - goto OTHER; - else -#endif - if (er.what != keyUp) - do_keystroke (er.what, er.message & charCodeMask, - key_code, modifiers, timestamp, &inev); - } - break; - - case kHighLevelEvent: - AEProcessAppleEvent (&er); - break; - - default: - OTHER: -#if TARGET_API_MAC_CARBON - { - OSStatus err; - - read_socket_inev = &inev; - err = SendEventToEventTarget (eventRef, toolbox_dispatcher); - read_socket_inev = NULL; - } -#endif - break; - } -#if TARGET_API_MAC_CARBON - ReleaseEvent (eventRef); -#endif - - if (inev.kind != NO_EVENT) - { - inev.timestamp = timestamp; - kbd_buffer_store_event_hold (&inev, hold_quit); - count++; - } - - if (do_help - && !(hold_quit && hold_quit->kind != NO_EVENT)) - { - Lisp_Object frame; - - if (f) - XSETFRAME (frame, f); - else - frame = Qnil; - - if (do_help > 0) - { - any_help_event_p = 1; - gen_help_event (help_echo_string, frame, help_echo_window, - help_echo_object, help_echo_pos); - } - else - { - help_echo_string = Qnil; - gen_help_event (Qnil, frame, Qnil, Qnil, 0); - } - count++; - } - } - - /* If the focus was just given to an autoraising frame, - raise it now. */ - /* ??? This ought to be able to handle more than one such frame. */ - if (pending_autoraise_frame) - { - x_raise_frame (pending_autoraise_frame); - pending_autoraise_frame = 0; - } - - if (mac_screen_config_changed) - { - mac_get_screen_info (dpyinfo); - mac_screen_config_changed = 0; - } - -#if !TARGET_API_MAC_CARBON - /* Check which frames are still visible. We do this here because - there doesn't seem to be any direct notification from the Window - Manager that the visibility of a window has changed (at least, - not in all cases). */ - { - Lisp_Object tail, frame; - - FOR_EACH_FRAME (tail, frame) - { - struct frame *f = XFRAME (frame); - - /* The tooltip has been drawn already. Avoid the - SET_FRAME_GARBAGED in mac_handle_visibility_change. */ - if (EQ (frame, tip_frame)) - continue; - - if (FRAME_MAC_P (f)) - mac_handle_visibility_change (f); - } - } -#endif - - --handling_signal; - UNBLOCK_INPUT; - return count; -} - /* Need to override CodeWarrior's input function so no conversion is done on newlines Otherwise compiled functions in .elc files will be @@ -12435,7 +8971,6 @@ __convert_from_newlines (unsigned char * p, size_t * n) } #endif -#ifdef MAC_OS8 void make_mac_terminal_frame (struct frame *f) { @@ -12515,7 +9050,7 @@ make_mac_terminal_frame (struct frame *f) Fcons (Fcons (Qbackground_color, build_string ("white")), Qnil)); } -#endif +#endif /* MAC_OS8 */ /*********************************************************************** @@ -12671,51 +9206,6 @@ x_delete_display (dpyinfo) } -static void -init_menu_bar () -{ -#ifdef MAC_OSX - OSStatus err; - MenuRef menu; - MenuItemIndex menu_index; - - err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1, - &menu, &menu_index); - if (err == noErr) - SetMenuItemCommandKey (menu, menu_index, false, 0); - EnableMenuCommand (NULL, kHICommandPreferences); - err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1, - &menu, &menu_index); - if (err == noErr) - { - SetMenuItemCommandKey (menu, menu_index, false, 0); - InsertMenuItemTextWithCFString (menu, NULL, - 0, kMenuItemAttrSeparator, 0); - InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"), - 0, 0, kHICommandAbout); - } -#else /* !MAC_OSX */ -#if TARGET_API_MAC_CARBON - SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout); -#endif -#endif -} - -#if USE_MAC_TSM -static void -init_tsm () -{ -#ifdef MAC_OSX - static InterfaceTypeList types = {kUnicodeDocument}; -#else - static InterfaceTypeList types = {kTextService}; -#endif - - NewTSMDocument (sizeof (types) / sizeof (types[0]), types, - &tsm_document_id, 0); -} -#endif - /* Set up use of X before we make the first connection. */ extern frame_parm_handler mac_frame_parm_handlers[]; @@ -12794,7 +9284,6 @@ mac_initialize () baud_rate = 19200; last_tool_bar_item = -1; - any_help_event_p = 0; /* Try to use interrupt input; if we can't, then start polling. */ Fset_input_mode (Qt, Qnil, Qt, Qnil); @@ -12802,22 +9291,17 @@ mac_initialize () BLOCK_INPUT; #if TARGET_API_MAC_CARBON - - install_application_handler (); - - init_menu_bar (); - -#if USE_MAC_TSM - init_tsm (); -#endif - #ifdef MAC_OSX init_coercion_handler (); - init_apple_event_handler (); - init_dm_notification_handler (); +#endif + install_application_handler (); + + mac_toolbox_initialize (); + +#ifdef MAC_OSX if (!inhibit_window_system) { static const ProcessSerialNumber psn = {0, kCurrentProcess}; From db4bb66a325e056a4223abbf00249a2a8c0e658f Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 01:59:20 +0000 Subject: [PATCH 12/56] (FRAME_OUTER_TO_INNER_DIFF_X, FRAME_OUTER_TO_INNER_DIFF_Y): Move to mactoolbox.c. (HOURGLASS_WIDTH, HOURGLASS_HEIGHT): Change to 15. (Fx_selection_owner_p): Add EXFUN. (install_window_handler, remove_window_handler, XSetWindowBackground): Remove externs. (do_apple_menu) [!TARGET_API_MAC_CARBON]: Likewise. (mac_prepare_for_quickdraw) [USE_CG_DRAWING]: Likewise. (x_raise_frame, x_lower_frame, mac_alert_sound_play) (install_application_handler, mac_get_frame_bounds, mac_get_frame_mouse) (mac_convert_frame_point_to_global, mac_set_frame_window_background) (mac_update_begin mac_update_end, mac_frame_up_to_date, x_flush) (mac_create_frame_window, mac_dispose_frame_window, mac_begin_clip) (mac_end_clip, mac_create_scroll_bar, mac_dispose_scroll_bar) (mac_set_scroll_bar_bounds, mac_redraw_scroll_bar, mac_fill_menubar) (create_and_show_popup_menu, mac_get_selection_from_symbol) (mac_valid_selection_target_p, mac_clear_selection) (mac_get_selection_ownership_info, mac_valid_selection_value_p) (mac_put_selection_value, mac_selection_has_target_p) (mac_get_selection_value, mac_get_selection_target_list): Add externs. (mac_update_proxy_icon, mac_show_hourglass, mac_hide_hourglass) (mac_reposition_hourglass, mac_file_dialog, create_and_show_dialog) (mac_dnd_default_known_types) [TARGET_API_MAC_CARBON]: Likewise. (mac_run_loop_run_once) [MAC_OSX]: Likewise. (mac_dialog) [!TARGET_API_MAC_CARBON]: Likewise. (mac_begin_cg_clip, mac_end_cg_clip) [USE_CG_DRAWING]: Likewise. (x_set_toolkit_scroll_bar_thumb) [!USE_TOOLKIT_SCROLL_BARS]: Likewise. (x_scroll_bar_set_handle) [!USE_TOOLKIT_SCROLL_BARS]: Likewise. --- src/macterm.h | 116 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 30 deletions(-) diff --git a/src/macterm.h b/src/macterm.h index c95d464544a..8b9eda7a3bb 100644 --- a/src/macterm.h +++ b/src/macterm.h @@ -379,12 +379,6 @@ typedef struct mac_output mac_output; /* This is the 'font_info *' which frame F has. */ #define FRAME_MAC_FONT_TABLE(f) (FRAME_MAC_DISPLAY_INFO (f)->font_table) -/* The difference in pixels between the top left corner of the - Emacs window (including possible window manager decorations) - and FRAME_MAC_WINDOW (f). */ -#define FRAME_OUTER_TO_INNER_DIFF_X(f) ((f)->x_pixels_diff) -#define FRAME_OUTER_TO_INNER_DIFF_Y(f) ((f)->y_pixels_diff) - /* Value is the smallest width of any character in any font on frame F. */ #define FRAME_SMALLEST_CHAR_WIDTH(F) \ @@ -557,8 +551,8 @@ struct scroll_bar { #define MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH (11) /* Size of hourglass controls */ -#define HOURGLASS_WIDTH (16) -#define HOURGLASS_HEIGHT (16) +#define HOURGLASS_WIDTH (15) +#define HOURGLASS_HEIGHT (15) /* Some constants that are used locally. */ /* Creator code for Emacs on Mac OS. */ @@ -632,6 +626,8 @@ extern int XParseGeometry P_ ((char *, int *, int *, unsigned int *, extern void x_set_window_size P_ ((struct frame *, int, int, int)); extern void x_set_mouse_position P_ ((struct frame *, int, int)); extern void x_set_mouse_pixel_position P_ ((struct frame *, int, int)); +extern void x_raise_frame P_ ((struct frame *)); +extern void x_lower_frame P_ ((struct frame *)); extern void x_make_frame_visible P_ ((struct frame *)); extern void x_make_frame_invisible P_ ((struct frame *)); extern void x_iconify_frame P_ ((struct frame *)); @@ -651,29 +647,12 @@ extern GC XCreateGC P_ ((Display *, void *, unsigned long, XGCValues *)); extern void XFreeGC P_ ((Display *, GC)); extern void XSetForeground P_ ((Display *, GC, unsigned long)); extern void XSetBackground P_ ((Display *, GC, unsigned long)); -extern void XSetWindowBackground P_ ((Display *, WindowRef, unsigned long)); extern void XDrawLine P_ ((Display *, Pixmap, GC, int, int, int, int)); extern void mac_clear_area P_ ((struct frame *, int, int, unsigned int, unsigned int)); extern void mac_unload_font P_ ((struct mac_display_info *, XFontStruct *)); -extern int mac_font_panel_visible_p P_ ((void)); -extern OSStatus mac_show_hide_font_panel P_ ((void)); -extern OSStatus mac_set_font_info_for_selection P_ ((struct frame *, int, int)); -extern OSStatus install_window_handler P_ ((WindowRef)); -extern void remove_window_handler P_ ((WindowRef)); extern OSStatus mac_post_mouse_moved_event P_ ((void)); -#if !TARGET_API_MAC_CARBON -extern void do_apple_menu P_ ((SInt16)); -#endif -#if USE_CG_DRAWING -extern void mac_prepare_for_quickdraw P_ ((struct frame *)); -#endif -extern void mac_get_window_bounds P_ ((struct frame *, Rect *, Rect *)); extern int mac_quit_char_key_p P_ ((UInt32, UInt32)); -#if USE_MAC_TOOLBAR -extern void update_frame_tool_bar P_ ((FRAME_PTR f)); -extern void free_frame_tool_bar P_ ((FRAME_PTR f)); -#endif #define FONT_TYPE_FOR_UNIBYTE(font, ch) 0 #define FONT_TYPE_FOR_MULTIBYTE(font, ch) 0 @@ -681,6 +660,7 @@ extern void free_frame_tool_bar P_ ((FRAME_PTR f)); /* Defined in macselect.c */ extern void x_clear_frame_selections P_ ((struct frame *)); +EXFUN (Fx_selection_owner_p, 1); /* Defined in macfns.c */ @@ -697,11 +677,6 @@ extern void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object)) extern void mac_update_title_bar P_ ((struct frame *, int)); extern Lisp_Object x_get_focus_frame P_ ((struct frame *)); -/* Defined in macmenu.c */ - -extern void x_activate_menubar P_ ((struct frame *)); -extern void free_frame_menubar P_ ((struct frame *)); - /* Defined in mac.c. */ extern void mac_clear_font_name_table P_ ((void)); @@ -733,5 +708,86 @@ extern Lisp_Object xrm_get_resource P_ ((XrmDatabase, const char *, extern XrmDatabase xrm_get_preference_database P_ ((const char *)); EXFUN (Fmac_get_preference, 4); +/* Defined in mactoolbox.c. */ + +extern void mac_alert_sound_play P_ ((void)); +extern OSStatus install_application_handler P_ ((void)); +extern void mac_get_window_bounds P_ ((struct frame *, Rect *, Rect *)); +extern Rect *mac_get_frame_bounds P_ ((struct frame *, Rect *)); +extern void mac_get_frame_mouse P_ ((struct frame *, Point *)); +extern void mac_convert_frame_point_to_global P_ ((struct frame *, int *, + int *)); +#if TARGET_API_MAC_CARBON +extern void mac_update_proxy_icon P_ ((struct frame *)); +#endif +extern void mac_set_frame_window_background P_ ((struct frame *, + unsigned long)); +extern void mac_update_begin P_ ((struct frame *)); +extern void mac_update_end P_ ((struct frame *)); +extern void mac_frame_up_to_date P_ ((struct frame *)); +extern void x_flush P_ ((struct frame *)); +extern void mac_create_frame_window P_ ((struct frame *, int)); +extern void mac_dispose_frame_window P_ ((struct frame *)); +#if USE_CG_DRAWING +extern CGContextRef mac_begin_cg_clip P_ ((struct frame *, GC)); +extern void mac_end_cg_clip P_ ((struct frame *)); +#endif +extern void mac_begin_clip P_ ((struct frame *, GC)); +extern void mac_end_clip P_ ((struct frame *, GC)); +extern void mac_create_scroll_bar P_ ((struct scroll_bar *, const Rect *, + Boolean)); +extern void mac_dispose_scroll_bar P_ ((struct scroll_bar *)); +extern void mac_set_scroll_bar_bounds P_ ((struct scroll_bar *, const Rect *)); +extern void mac_redraw_scroll_bar P_ ((struct scroll_bar *)); +#ifdef USE_TOOLKIT_SCROLL_BARS +extern void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *, + int, int, int)); +#else +extern void x_scroll_bar_set_handle P_ ((scroll_bar *, int, int, int)); +#endif +#if USE_MAC_FONT_PANEL +extern int mac_font_panel_visible_p P_ ((void)); +extern OSStatus mac_show_hide_font_panel P_ ((void)); +extern OSStatus mac_set_font_info_for_selection P_ ((struct frame *, int, int)); +#endif +#ifdef MAC_OSX +extern Boolean mac_run_loop_run_once P_ ((EventTimeout)); +#endif +#if USE_MAC_TOOLBAR +extern void update_frame_tool_bar P_ ((FRAME_PTR f)); +extern void free_frame_tool_bar P_ ((FRAME_PTR f)); +#endif +#if TARGET_API_MAC_CARBON +extern void mac_show_hourglass P_ ((struct frame *)); +extern void mac_hide_hourglass P_ ((struct frame *)); +extern void mac_reposition_hourglass P_ ((struct frame *)); +extern Lisp_Object mac_file_dialog P_ ((Lisp_Object, Lisp_Object, Lisp_Object, + Lisp_Object, Lisp_Object)); +#endif +extern void x_activate_menubar P_ ((struct frame *)); +extern void free_frame_menubar P_ ((struct frame *)); +extern void mac_fill_menubar P_ ((widget_value *, int)); +extern void create_and_show_popup_menu P_ ((FRAME_PTR, widget_value *, + int, int, int)); +#if TARGET_API_MAC_CARBON +extern void create_and_show_dialog P_ ((FRAME_PTR, widget_value *)); +#else +extern int mac_dialog P_ ((widget_value *)); +#endif +extern OSStatus mac_get_selection_from_symbol P_ ((Lisp_Object, int, + Selection *)); +extern int mac_valid_selection_target_p P_ ((Lisp_Object)); +extern OSStatus mac_clear_selection P_ ((Selection *)); +extern Lisp_Object mac_get_selection_ownership_info P_ ((Selection)); +extern int mac_valid_selection_value_p P_ ((Lisp_Object, Lisp_Object)); +extern OSStatus mac_put_selection_value P_ ((Selection, Lisp_Object, + Lisp_Object)); +extern int mac_selection_has_target_p P_ ((Selection, Lisp_Object)); +extern Lisp_Object mac_get_selection_value P_ ((Selection, Lisp_Object)); +extern Lisp_Object mac_get_selection_target_list P_ ((Selection)); +#if TARGET_API_MAC_CARBON +extern Lisp_Object mac_dnd_default_known_types P_ ((void)); +#endif + /* arch-tag: 6b4ca125-5bef-476d-8ee8-31ed808b7e79 (do not change this comment) */ From 9e13f0c32e8ac3b0d91bb60ffad3151063cc16e8 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sun, 6 Apr 2008 02:04:32 +0000 Subject: [PATCH 13/56] *** empty log message *** --- src/ChangeLog | 284 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 283 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index 2082f8e27f2..ea69708e3fe 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,285 @@ +2008-04-06 YAMAMOTO Mitsuharu + + * Makefile.in (MAC_OBJ): Add mactoolbox.o. + (mactoolbox.o): New target. + + * mac.c [MAC_OSX] (select_and_poll_event, sys_select): + Use mac_run_loop_run_once instead of CFRunLoopRunInMode. + + * macfns.c (x_set_background_color, mac_window, x_create_tip_frame): + Use mac_set_frame_window_background instead of XSetWindowBackground. + (x_set_tool_bar_lines) [USE_MAC_TOOLBAR]: + Use mac_is_window_toolbar_visible instead of IsWindowToolbarVisible. + (x_set_name_internal) [TARGET_API_MAC_CARBON]: Use mac_set_window_title + instead of SetWindowTitleWithCFString. + (mac_update_proxy_icon) [TARGET_API_MAC_CARBON]: Remove BLOCK_INPUT. + Move function to mactoolbox.c. + (mac_update_title_bar) [TARGET_API_MAC_CARBON]: + Use mac_set_window_modified instead of SetWindowModified. + Add BLOCK_INPUT around mac_set_window_modified/mac_update_proxy_icon. + (mac_window, x_create_tip_frame): Use mac_create_frame_window. + (Fx_focus_frame): Use mac_front_non_floating_window instead of + FrontNonFloatingWindow. Use mac_activate_window instead of + ActivateWindow. Use mac_active_non_floating_window instead of + ActiveNonFloatingWindow. + (show_hourglass, hide_hourglass) [TARGET_API_MAC_CARBON]: + Use mac_show_hourglass and mac_hide_hourglass. + (compute_tip_xy) [TARGET_API_MAC_CARBON]: Use mac_get_global_mouse + instead of GetGlobalMouse. + (Fx_show_tip): Use mac_move_window/mac_size_window/mac_show_window + instead of MoveWindow/SizeWindow/ShowWindow, respectively. + Use mac_bring_window_to_front instead of BringToFront. + (Qfile_name_history) [TARGET_API_MAC_CARBON]: Move extern to + mactoolbox.c. + (Fx_file_dialog) [TARGET_API_MAC_CARBON]: Move function body to + mac_file_dialog in mactoolbox.c. Use mac_file_dialog. + (mac_nav_event_callback) [TARGET_API_MAC_CARBON]: Move function to + mactoolbox.c. + + * macgui.h [!HAVE_CARBON]: Include Quickdraw.h instead of QuickDraw.h. + (XtPointer): Move typedef from macmenu.c. + (enum button_type): Move enum from macmenu.c. + (widget_value): Move typedef from macmenu.c. + (M_APPLE, I_ABOUT, EXTRA_STACK_ALLOC, ARGV_STRING_LIST_ID) + (DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN, DIALOG_RIGHT_MARGIN) + (DIALOG_BOTTOM_MARGIN, DIALOG_MIN_INNER_WIDTH, DIALOG_MAX_INNER_WIDTH) + (DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE) + (DIALOG_BUTTON_BUTTON_VERTICAL_SPACE, DIALOG_BUTTON_MIN_WIDTH) + (DIALOG_TEXT_MIN_HEIGHT, DIALOG_TEXT_BUTTONS_VERTICAL_SPACE) + (DIALOG_ICON_WIDTH, DIALOG_ICON_HEIGHT, DIALOG_ICON_LEFT_MARGIN) + (DIALOG_ICON_TOP_MARGIN): Move defines from macmenu.c. + (Selection): Move typedef from macselect.c. + (RAM_TOO_LARGE_ALERT_ID, ABOUT_ALERT_ID) [MAC_OS8]: Move defines from + macterm.c. + (mac_set_window_title, mac_set_window_modified, mac_is_window_visible) + (mac_is_window_collapsed, mac_bring_window_to_front) + (mac_send_window_behind, mac_hide_window, mac_show_window) + (mac_collapse_window, mac_front_non_floating_window) + (mac_active_non_floating_window, mac_activate_window) + (mac_move_window_structure, mac_move_window, mac_size_window) + (mac_get_global_mouse, mac_is_window_toolbar_visible): New defines. + + * macmenu.c [!TARGET_API_MAC_CARBON]: Move includes to mactoolbox.c. + (enum mac_menu_kind): Move enum to mactoolbox.c. + (min_menu_id): Move variable to mactoolbox.c. + (quit_dialog_event_loop) [TARGET_API_MAC_CARBON]: Likewise. + (DIALOG_WINDOW_RESOURCE): Move define to mactoolbox.c. + (DIALOG_BUTTON_COMMAND_ID_OFFSET, DIALOG_BUTTON_COMMAND_ID_P) + (DIALOG_BUTTON_COMMAND_ID_VALUE, DIALOG_BUTTON_MAKE_COMMAND_ID) + [TARGET_API_MAC_CARBON]: Likewise. + (XtPointer): Move typedef to macgui.h. + (enum button_type): Move enum to macgui.h. + (widget_value): Move typedef to macgui.h. + (DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN, DIALOG_RIGHT_MARGIN) + (DIALOG_BOTTOM_MARGIN, DIALOG_MIN_INNER_WIDTH, DIALOG_MAX_INNER_WIDTH) + (DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE) + (DIALOG_BUTTON_BUTTON_VERTICAL_SPACE, DIALOG_BUTTON_MIN_WIDTH) + (DIALOG_TEXT_MIN_HEIGHT, DIALOG_TEXT_BUTTONS_VERTICAL_SPACE) + (DIALOG_ICON_WIDTH, DIALOG_ICON_HEIGHT, DIALOG_ICON_LEFT_MARGIN) + (DIALOG_ICON_TOP_MARGIN): Move defines to macgui.h. + (popup_activated_flag): Make variable non-static. + (x_activate_menubar, install_menu_quit_handler, pop_down_menu) + (add_menu_item, fill_menu, dispose_menus): + Move functions to mactoolbox.c. + (restore_show_help_function, menu_target_item_handler) + (install_menu_target_item_handler, mac_handle_dialog_event) + (install_dialog_event_handler, pop_down_dialog, create_and_show_dialog) + [TARGET_API_MAC_CARBON]: Likewise. + (menu_quit_handler) [MAC_OS_X_VERSION_MAX_ALLOWED >= 1030]: Likewise. + (mac_dialog) [!TARGET_API_MAC_CARBON]: Likewise. + (find_and_call_menu_selection, name_is_separator): Make function + non-static. + (Vshow_help_function, timer_check) [TARGET_API_MAC_CARBON]: Move extern + to mactoolbox.c. + (set_frame_menubar): Don't call install_menu_quit_handler. + (menu_item_selection): New variable. + (mac_menu_show): Use create_and_show_popup_menu. + (create_and_show_dialog) [TARGET_API_MAC_CARBON]: Don't return + selection but set variable menu_item_selection. All uses changed. + (mac_fill_menubar): Rename from fill_menubar. All uses changed. + Call install_menu_quit_handler. Move to mactoolbox.c. + + * macselect.c [!TARGET_API_MAC_CARBON]: Don't include Scrap.h. + (Selection): Move typedef to macgui.h. + (Vselection_converter_alist, Qmac_scrap_name, Qmac_ostype) + (Vmac_apple_event_map, Qmac_apple_event_class, Qmac_apple_event_id): + Make variables non-static. + (Vmac_dnd_known_types) [TARGET_API_MAC_CARBON]: Likewise. + (mac_handle_apple_event, cleanup_all_suspended_apple_events): + Make functions non-static. + (Vmac_service_selection) [MAC_OSX]: Likewise. + (mac_get_selection_from_symbol, get_flavor_type_from_symbol) + (mac_valid_selection_target_p, mac_clear_selection) + (mac_get_selection_ownership_info, mac_valid_selection_value_p) + (mac_put_selection_value, mac_selection_has_target_p) + (mac_get_selection_value, mac_get_selection_target_list) + (init_apple_event_handler, install_drag_handler, remove_drag_handler): + Move functions to mactoolbox.c. + (mac_do_track_drag, mac_do_receive_drag) [TARGET_API_MAC_CARBON]: + Likewise. + (copy_scrap_flavor_data, mac_handle_service_event) + (install_service_handler) [MAC_OSX]: Likewise. + (syms_of_macselect) : + Use mac_dnd_default_known_types. + + * macterm.c (mac_end_cg_clip): Add argument F. All uses changed. + (mac_begin_cg_clip, mac_end_cg_clip): Allow null GC. + (mac_invert_rectangle, mac_compute_glyph_string_overhangs) + (mac_load_query_font): Use them instead of SetPortWindowPort. + (mac_clear_window) [!USE_CG_DRAWING]: Likewise. + (mac_draw_image_string_cg): Call CGContextSetTextMatrix. + (x_update_begin, x_update_end): Call mac_update_begin and + mac_update_end. + (XTframe_up_to_date): Call mac_frame_up_to_date. + (XTring_bell): Use mac_alert_sound_play. + (note_mouse_movement): Use mac_get_frame_bounds. + (XTmouse_position): Use mac_get_frame_mouse. + (x_scroll_bar_create): Use mac_create_scroll_bar. + (x_scroll_bar_remove): Use mac_dispose_scroll_bar. + (XTset_vertical_scroll_bar): Use mac_set_scroll_bar_bounds and + mac_redraw_scroll_bar. + (mac_move_window_with_gravity) [USE_MAC_TOOLBAR]: Use mac_move_window + instead of MoveWindow. + (mac_handle_size_change) [TARGET_API_MAC_CARBON]: + Use mac_reposition_hourglass. + (x_set_offset): Use mac_move_window_structure instead of + MoveWindowStructure. + (x_set_window_size): Use mac_size_window instead of SizeWindow. + (x_set_mouse_pixel_position) [MAC_OSX]: + Use mac_convert_frame_point_to_global. + (x_raise_frame): Use mac_bring_window_to_front instead of BringToFront. + (x_lower_frame): Use mac_send_window_behind instead of SendBehind. + (mac_handle_visibility_change): Use Window instead of WindowRef. + Use mac_is_window_visible/mac_is_window_collapsed instead of + IsWindowVisible/IsWindowCollapsed, respectively. + Use mac_collapse_window/mac_show_window instead of + CollapseWindow/ShowWindow, respectively. + (x_make_frame_invisible): Use mac_hide_window instead of HideWindow. + (x_iconify_frame): Use mac_show_window instead of ShowWindow. + Use mac_collapse_window instead of CollapseWindow. + (x_free_frame_resources): Use Window instead of WindowRef. + Use mac_dispose_frame_window. Clean up focus-related variables before + calling mac_dispose_frame_window. + (do_zoom_window) [MAC_OS8]: Use mac_clear_area instead of + mac_clear_window. + (mac_initialize): Use mac_toolbox_initialize instead of + initializing any_help_event_p and calling init_apple_event_handler, + init_tsm, and init_menu_bar. + (any_help_event_p, last_window, save_port_clip_region) + (read_socket_inev, saved_menu_event_location): Move variables to + mactoolbox.c. + (last_scroll_bar_part, scroll_bar_timer) + (scroll_bar_timer_event_posted_p) [USE_TOOLKIT_SCROLL_BARS]: Likewise. + (font_panel_shown_p) [USE_MAC_FONT_PANEL]: Likewise. + (tsm_document_id) [USE_MAC_TSM]: Likewise. + (mouse_region) [!TARGET_API_MAC_CARBON]: Likewise. + (mac_window_to_frame, DEFAULT_NUM_COLS, MIN_DOC_SIZE, MAX_DOC_SIZE): + Move defines to mactoolbox.c. + (FRAME_CG_CONTEXT) [USE_CG_DRAWING]: Likewise. + (SCROLL_BAR_FIRST_DELAY, SCROLL_BAR_CONTINUOUS_DELAY) + [USE_TOOLKIT_SCROLL_BARS]: Likewise. + (TOOLBAR_IDENTIFIER, TOOLBAR_ICON_ITEM_IDENTIFIER) + (TOOLBAR_ITEM_COMMAND_ID_OFFSET, TOOLBAR_ITEM_COMMAND_ID_P) + (TOOLBAR_ITEM_COMMAND_ID_VALUE, TOOLBAR_ITEM_MAKE_COMMAND_ID) + [USE_MAC_TOOLBAR]: Likewise. + (M_APPLE, I_ABOUT, EXTRA_STACK_ALLOC, ARGV_STRING_LIST_ID) + (RAM_TOO_LARGE_ALERT_ID, ABOUT_ALERT_ID): Move defines to macgui.h + (x_flush, is_emacs_window, mac_begin_clip, mac_end_clip) + (x_scroll_bar_handle_click, x_scroll_bar_report_motion) + (mac_get_window_bounds, do_window_update, is_emacs_window) + (do_grow_window, do_zoom_window, install_window_handler) + (remove_window_handler, XTread_socket, init_menu_bar): Move functions + to mactoolbox.c. + (mac_flush_display_optional, mac_begin_cg_clip, mac_end_cg_clip) + (mac_prepare_for_quickdraw) [USE_CG_DRAWING]: Likewise. + (mac_scroll_area, mac_event_to_emacs_modifiers, mac_get_mouse_btn) + (mac_convert_event_ref, mac_get_ideal_size, mac_store_drag_event) + (mac_handle_window_event, mac_handle_keyboard_event) + (mac_handle_command_event, mac_handle_mouse_event) + (install_application_handler, mac_post_mouse_moved_event) + [TARGET_API_MAC_CARBON]: Likewise. + (scroll_bar_timer_callback, install_scroll_bar_timer) + (set_scroll_bar_timer, control_part_code_to_scroll_bar_part) + (construct_scroll_bar_click, get_control_part_bounds) + (x_scroll_bar_handle_press, x_scroll_bar_handle_release) + (x_scroll_bar_handle_drag, x_set_toolkit_scroll_bar_thumb) + [USE_TOOLKIT_SCROLL_BARS]: Likewise. + (x_scroll_bar_set_handle, x_scroll_bar_note_movement) + [!USE_TOOLKIT_SCROLL_BARS]: Likewise. + (mac_handle_toolbar_event, mac_create_frame_tool_bar) + (update_frame_tool_bar, free_frame_tool_bar) + (mac_tool_bar_note_mouse_movement, mac_handle_toolbar_command_event) + [USE_MAC_TOOLBAR]: Likewise. + (mac_font_panel_visible_p, mac_handle_font_event) + (mac_show_hide_font_panel, mac_set_font_info_for_selection) + [USE_MAC_FONT_PANEL]: Likewise. + (mac_handle_text_input_event, init_tsm) [USE_MAC_TSM]: Likewise. + (do_apple_menu, mac_wait_next_event) [!TARGET_API_MAC_CARBON]: Likewise. + (mac_store_service_event) [MAC_OSX]: Likewise. + (last_mouse_glyph, last_mouse_glyph_frame, last_mouse_scroll_bar) + (last_mouse_movement_time, input_signal_count) + (mac_screen_config_changed, Qhi_command, Qtoolbar_switch_mode) + (Qservice, Qpaste, Qperform, keycode_to_xkeysym_table): Make variables + non-static. + (Qpanel_closed, Qselection) [USE_MAC_FONT_PANEL]: Likewise. + (Qtext_input, Vmac_ts_active_input_overlay, Qupdate_active_input_area) + (Qunicode_for_key_event, Vmac_ts_script_language_on_focus) + (saved_ts_script_language_on_focus) [USE_MAC_TSM]: Likewise. + (mac_focus_changed, note_mouse_movement, mac_focus_frame) + (mac_handle_origin_change, mac_handle_size_change) + (mac_handle_visibility_change, mac_to_emacs_modifiers) + (mac_mapped_modifiers, mac_get_emulated_btn, do_keystroke) + (mac_get_screen_info): Make functions non-static. + (mac_move_window_with_gravity, mac_get_window_origin_with_gravity) + (mac_image_spec_to_cg_image) [USE_MAC_TOOLBAR]: Likewise. + (mac_store_event_ref_as_apple_event) [TARGET_API_MAC_CARBON]: Likewise. + (Qwindow, mac_ready_for_apple_events): Move externs to mactoolbox.c. + (Qbefore_string) [USE_MAC_TSM]: Likewise. + (mac_toolbox_initialize, x_scroll_bar_report_motion, XTread_socket): + Add externs. + (mac_flush_display_optional) [USE_CG_DRAWING]: Likewise. + (install_drag_handler, remove_drag_handler, install_service_handler) + (install_menu_target_item_handler): Remove externs. + (XSetWindowBackground): Rename to mac_set_frame_window_background. + Take frame as argument instead of display and window. + Move to mactoolbox.c. + (mac_restore_keyboard_input_source, mac_save_keyboard_input_source) + [USE_MAC_TSM]: New functions created from mac_tsm_resume and + mac_tsm_suspend, respectively. + (mac_tsm_resume, mac_tsm_suspend) [USE_MAC_TSM]: Use them. + Move to mactoolbox.c. + + * macterm.h (FRAME_OUTER_TO_INNER_DIFF_X, FRAME_OUTER_TO_INNER_DIFF_Y): + Move to mactoolbox.c. + (HOURGLASS_WIDTH, HOURGLASS_HEIGHT): Change to 15. + (Fx_selection_owner_p): Add EXFUN. + (install_window_handler, remove_window_handler, XSetWindowBackground): + Remove externs. + (do_apple_menu) [!TARGET_API_MAC_CARBON]: Likewise. + (mac_prepare_for_quickdraw) [USE_CG_DRAWING]: Likewise. + (x_raise_frame, x_lower_frame, mac_alert_sound_play) + (install_application_handler, mac_get_frame_bounds, mac_get_frame_mouse) + (mac_convert_frame_point_to_global, mac_set_frame_window_background) + (mac_update_begin mac_update_end, mac_frame_up_to_date, x_flush) + (mac_create_frame_window, mac_dispose_frame_window, mac_begin_clip) + (mac_end_clip, mac_create_scroll_bar, mac_dispose_scroll_bar) + (mac_set_scroll_bar_bounds, mac_redraw_scroll_bar, mac_fill_menubar) + (create_and_show_popup_menu, mac_get_selection_from_symbol) + (mac_valid_selection_target_p, mac_clear_selection) + (mac_get_selection_ownership_info, mac_valid_selection_value_p) + (mac_put_selection_value, mac_selection_has_target_p) + (mac_get_selection_value, mac_get_selection_target_list): Add externs. + (mac_update_proxy_icon, mac_show_hourglass, mac_hide_hourglass) + (mac_reposition_hourglass, mac_file_dialog, create_and_show_dialog) + (mac_dnd_default_known_types) [TARGET_API_MAC_CARBON]: Likewise. + (mac_run_loop_run_once) [MAC_OSX]: Likewise. + (mac_dialog) [!TARGET_API_MAC_CARBON]: Likewise. + (mac_begin_cg_clip, mac_end_cg_clip) [USE_CG_DRAWING]: Likewise. + (x_set_toolkit_scroll_bar_thumb) [!USE_TOOLKIT_SCROLL_BARS]: Likewise. + (x_scroll_bar_set_handle) [!USE_TOOLKIT_SCROLL_BARS]: Likewise. + + * mactoolbox.c: New file. + 2008-04-05 Chong Yidong * search.c (compile_pattern_1): Treat non-nil and non-string of @@ -132,7 +414,7 @@ (x_make_frame_visible) [TARGET_API_MAC_CARBON]: Move code for repositioning window to mac_handle_window_event. (x_make_frame_invisible) [TARGET_API_MAC_CARBON]: Move code for - saving window location to mac_handle_window_event + saving window location to mac_handle_window_event. [USE_MAC_FONT_PANEL] (mac_show_hide_font_panel): Install handler here. (install_menu_target_item_handler): Remove argument in extern. [TARGET_API_MAC_CARBON] (mac_event_to_emacs_modifiers): From 088a2895a9ad972c74d21c558c34405d50ad379a Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Sun, 6 Apr 2008 20:31:40 +0000 Subject: [PATCH 14/56] *** empty log message *** --- lisp/ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 321937d0362..7dbe46ab922 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,12 @@ +2008-04-06 Alan Mackenzie + + * progmodes/cc-langs.el (c-before-font-lock-function): Correct a + typo in the doc string. + + * progmodes/cc-mode.el (c-extend-after-change-region): New + function, used in font-lock-extend-after-change-region-function, + thus superseding advice on the Font Lock after change functions. + 2008-04-06 Chong Yidong * dired-aux.el (dired-overwrite-confirmed): Supply initial value. From afd2c2fc7447755c7cad3a8f78df36bc3f5bca45 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Sun, 6 Apr 2008 20:33:05 +0000 Subject: [PATCH 15/56] (c-extend-after-change-region): New function, used in font-lock-extend-after-change-region-function, thus superseding advice on the Font Lock after change functions. --- lisp/progmodes/cc-mode.el | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index b122b392dd5..36a69acf407 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -597,7 +597,9 @@ that requires a literal mode spec at compile time." (make-local-hook 'before-change-functions) (add-hook 'before-change-functions 'c-before-change nil t) (make-local-hook 'after-change-functions) - (add-hook 'after-change-functions 'c-after-change nil t)) + (add-hook 'after-change-functions 'c-after-change nil t) + (setq font-lock-extend-after-change-region-function + 'c-extend-after-change-region)) ; Currently (2008-04), only used by AWK. (defun c-setup-doc-comment-style () "Initialize the variables that depend on the value of `c-doc-comment-style'." @@ -1003,19 +1005,17 @@ This does not load the font-lock package. Use after (make-local-hook 'font-lock-mode-hook) (add-hook 'font-lock-mode-hook 'c-after-font-lock-init nil t)) -(defmacro c-advise-fl-for-region (function) - `(defadvice ,function (before get-awk-region activate) -;; When font-locking an AWK Mode buffer, make sure that any string/regexp is -;; completely font-locked. - (when (eq major-mode 'awk-mode) - (save-excursion - (ad-set-arg 1 c-new-END) ; end - (ad-set-arg 0 c-new-BEG))))) ; beg - -(c-advise-fl-for-region font-lock-after-change-function) -(c-advise-fl-for-region jit-lock-after-change) -(c-advise-fl-for-region lazy-lock-defer-rest-after-change) -(c-advise-fl-for-region lazy-lock-defer-line-after-change) +(defun c-extend-after-change-region (beg end old-len) + "Extend the region to be fontified, if necessary." + ;; Note: the parameters are ignored here. This somewhat indirect + ;; implementation exists because it is minimally different from the + ;; stand-alone CC Mode which, lacking + ;; font-lock-extend-after-change-region-function, is forced to use advice + ;; instead. + ;; + ;; Of the seven CC Mode languages, currently (2008-04) only AWK Mode makes + ;; non-null use of this function. + (cons c-new-BEG c-new-END)) ;; Support for C From 772a35442b4ef53de2cf2ae74939ae41c5da76c4 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Sun, 6 Apr 2008 20:34:25 +0000 Subject: [PATCH 16/56] (c-before-font-lock-function): Correct a typo in the doc string. --- lisp/progmodes/cc-langs.el | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 73040221eaa..c1e7af56998 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -445,7 +445,7 @@ exit; on entry, the buffer will have been widened and match-data will have been saved; the return value is ignored. The function may extend the region to be fontified by setting the -buffer local variables c-old-BEG and c-old-END. +buffer local variables c-new-BEG and c-new-END. The function is called even when font locking is disabled. @@ -728,13 +728,14 @@ definition, or nil if the language doesn't have any." "define")) (c-lang-defconst c-opt-cpp-macro-define-start - ;; Regexp matching everything up to the macro body of a cpp define, - ;; or the end of the logical line if there is none. Set if - ;; c-opt-cpp-macro-define is. + ;; Regexp matching everything up to the macro body of a cpp define, or the + ;; end of the logical line if there is none. Submatch 1 is the name of the + ;; macro. Set if c-opt-cpp-macro-define is. t (if (c-lang-const c-opt-cpp-macro-define) (concat (c-lang-const c-opt-cpp-prefix) (c-lang-const c-opt-cpp-macro-define) - "[ \t]+\\(\\sw\\|_\\)+\\(\([^\)]*\)\\)?" + "[ \t]+\\(\\(\\sw\\|_\\)+\\)\\(\([^\)]*\)\\)?" + ;; ^ ^ #defined name "\\([ \t]\\|\\\\\n\\)*"))) (c-lang-defvar c-opt-cpp-macro-define-start (c-lang-const c-opt-cpp-macro-define-start)) From 5e1a21c7428e3d1d6a1e3d3a2d1fef0839e3c6d2 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Sun, 6 Apr 2008 21:01:07 +0000 Subject: [PATCH 17/56] * dired.el (dired-dnd-handle-local-file): Obey dired-backup-overwrite for copy, move, and link operations. * dired-aux.el (dired-overwrite-confirmed): Undo last change. --- lisp/ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 7dbe46ab922..d26ac95a6a7 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2008-04-06 Chong Yidong + + * dired.el (dired-dnd-handle-local-file): Obey + dired-backup-overwrite for copy, move, and link operations. + + * dired-aux.el (dired-overwrite-confirmed): Undo last change. + 2008-04-06 Alan Mackenzie * progmodes/cc-langs.el (c-before-font-lock-function): Correct a From 3b1b11e968c38c794e550a7689b3ca917b542d25 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Sun, 6 Apr 2008 21:01:54 +0000 Subject: [PATCH 18/56] (dired-dnd-handle-local-file): Obey dired-backup-overwrite for copy, move, and link operations. --- lisp/dired.el | 73 +++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/lisp/dired.el b/lisp/dired.el index e184b3bc0ea..0daaf2d3987 100644 --- a/lisp/dired.el +++ b/lisp/dired.el @@ -3236,7 +3236,7 @@ Anything else means ask for each directory." (defun dired-dnd-popup-notice () (message-box - "Recursive copies not enabled.\nSee variable dired-recursive-copies.")) + "Dired recursive copies are currently disabled.\nSee the variable `dired-recursive-copies'.")) (defun dired-dnd-do-ask-action (uri) @@ -3261,37 +3261,46 @@ URI is the file to handle, ACTION is one of copy, move, link or ask. Ask means pop up a menu for the user to select one of copy, move or link." (require 'dired-aux) (let* ((from (dnd-get-local-file-name uri t)) - (to (if from (concat (dired-current-directory) - (file-name-nondirectory from)) - nil))) - (if from - (cond ((or (eq action 'copy) - (eq action 'private)) ; Treat private as copy. - - ;; If copying a directory and dired-recursive-copies is nil, - ;; dired-copy-file silently fails. Pop up a notice. - (if (and (file-directory-p from) - (not dired-recursive-copies)) - (dired-dnd-popup-notice) - (progn - (dired-copy-file from to 1) - (dired-relist-entry to) - action))) - - ((eq action 'move) - (dired-rename-file from to 1) - (dired-relist-entry to) - action) - - ((eq action 'link) - (make-symbolic-link from to 1) - (dired-relist-entry to) - action) - - ((eq action 'ask) - (dired-dnd-do-ask-action uri)) - - (t nil))))) + (to (when from + (concat (dired-current-directory) + (file-name-nondirectory from))))) + (when from + (cond ((eq action 'ask) + (dired-dnd-do-ask-action uri)) + ;; If copying a directory and dired-recursive-copies is + ;; nil, dired-copy-file fails. Pop up a notice. + ((and (memq action '(copy private)) + (file-directory-p from) + (not dired-recursive-copies)) + (dired-dnd-popup-notice)) + ((memq action '(copy private move link)) + (let ((overwrite (and (file-exists-p to) + (y-or-n-p + (format "Overwrite existing file `%s'? " to)))) + ;; Binding dired-overwrite-confirmed to nil makes + ;; dired-handle-overwrite a no-op. We instead use + ;; y-or-n-p, which pops a graphical menu. + dired-overwrite-confirmed backup-file) + (when (and overwrite + ;; d-b-o is defined in dired-aux. + (boundp 'dired-backup-overwrite) + dired-backup-overwrite + (setq backup-file + (car (find-backup-file-name to))) + (or (eq dired-backup-overwrite 'always) + (y-or-n-p + (format + "Make backup for existing file `%s'? " to)))) + (rename-file to backup-file 0) + (dired-relist-entry backup-file)) + (cond ((memq action '(copy private)) + (dired-copy-file from to overwrite)) + ((eq action 'move) + (dired-rename-file from to overwrite)) + ((eq action 'link) + (make-symbolic-link from to overwrite))) + (dired-relist-entry to) + action)))))) (defun dired-dnd-handle-file (uri action) "Copy, move or link a file to the dired directory if it is a local file. From 9a628d95f32093923f8a21da03d4e04b0aec8380 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Sun, 6 Apr 2008 21:05:17 +0000 Subject: [PATCH 19/56] (dired-overwrite-confirmed): Undo last change. --- lisp/dired-aux.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index d7d1d607999..407e7296adc 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -1129,7 +1129,10 @@ Special value `always' suppresses confirmation." (other :tag "ask" t)) :group 'dired) -(defvar dired-overwrite-confirmed nil) +;; This is a fluid var used in dired-handle-overwrite. It should be +;; let-bound whenever dired-copy-file etc are called. See +;; dired-create-files for an example. +(defvar dired-overwrite-confirmed) (defun dired-handle-overwrite (to) ;; Save old version of file TO that is to be overwritten. From bfea922885434e9af85abc164b836cbe639955f2 Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Mon, 7 Apr 2008 07:13:07 +0000 Subject: [PATCH 20/56] Add arch tagline --- src/mactoolbox.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mactoolbox.c b/src/mactoolbox.c index e1fa79ac8be..6b4d22049a9 100644 --- a/src/mactoolbox.c +++ b/src/mactoolbox.c @@ -6206,3 +6206,6 @@ mac_toolbox_initialize () init_tsm (); #endif } + +/* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516 + (do not change this comment) */ From da0dae760a7e20dd8093ce5368e1ebd58704cf4b Mon Sep 17 00:00:00 2001 From: Carsten Dominik Date: Tue, 8 Apr 2008 07:31:31 +0000 Subject: [PATCH 21/56] *** empty log message *** --- lisp/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index d26ac95a6a7..e8cddb5e0cb 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,4 @@ + 2008-04-06 Chong Yidong * dired.el (dired-dnd-handle-local-file): Obey From fa5b76fba2a49bd42757bf19b47339bec56cdbbc Mon Sep 17 00:00:00 2001 From: Carsten Dominik Date: Tue, 8 Apr 2008 07:43:01 +0000 Subject: [PATCH 22/56] *** empty log message *** --- lisp/ChangeLog | 659 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 659 insertions(+) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e8cddb5e0cb..6ff322cd958 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,662 @@ +2008-04-08 Carsten Dominik + + * textmodes/org-export-latex.el: New file. + + * textmodes/org-irc.el: New file. + + * textmodes/org-mac-message.el: New file. + + * textmodes/org-publish.el: New file. + + * textmodes/org.el (org-agenda-collect-markers) + (org-create-marker-find-array) + (org-check-agenda-marker-table, org-extract-log-state-settings) + (org-nofm-to-completion, org-refile-goto-last-stored) + (org-export-html-convert-special-strings, org-first-list-item-p) + (org-imenu-new-marker, org-imenu-get-tree) + (org-speedbar-set-agenda-restriction) + (org-agenda-set-restriction-lock) + (org-agenda-remove-restriction-lock) + (org-agenda-maybe-redo, org-compute-latex-and-specials-regexp) + (org-do-latex-and-special-faces, org-read-date-display) + (org-select-remember-template, org-agenda-copy-local-variable) + (org-read-date-get-relative, org-columns-cleanup-item) + (org-find-entry-with-id) + (org-insert-columns-dblock, org-listtable-to-string) + (org-dblock-write:columnview, org-columns-capture-view) + (org-edit-headline, org-parse-local-options) + (org-in-clocktable-p, org-property-or-variable-value) + (org-get-tags-string, org-up-heading-safe) + (org-fast-todo-selection, org-get-wdays) + (org-switch-to-buffer-other-window, org-agenda-deadline-face) + (org-add-link-type, org-columns-content, org-columns-widen) + (org-columns-next-allowed-value, org-columns-edit-allowed) + (org-columns-store-format) + (org-columns-uncompile-format, org-columns-redo) + (org-columns-edit-attributes, org-delete-property) + (org-set-property, org-columns-update, org-columns-compute) + (org-columns-eval) + (org-columns-not-in-agenda, org-columns-compute-all) + (org-property-next-allowed-value) + (org-columns-compile-format, org-fill-paragraph-experimental) + (org-string-to-number, org-property-action, org-columns-move-left) + (org-columns-new) + (org-column-number-to-string, org-property-previous-allowed-value) + (org-at-property-p, org-columns-delete) + (org-columns-previous-allowed-value) + (org-columns-move-right, org-columns-narrow) + (org-property-get-allowed-values) + (org-verify-version, org-column-string-to-number) + (org-delete-property-globally) + (org-get-property-block, org-entry-properties, org-entry-get) + (org-entry-delete, org-entry-get-with-inheritance) + (org-entry-put, org-buffer-property-keys, org-new-column-overlay) + (org-overlay-columns) + (org-overlay-columns-title, org-remove-column-overlays) + (org-column-show-value, org-column-quit, org-column-edit) + (org-cached-entry-get, org-table-put-field-property) + (org-get-columns-autowidth-alist, turn-on-orgstruct) + (orgstruct-error, orgstruct-setup) + (orgstruct-make-binding, org-context-p, org-get-local-variables) + (org-run-like-in-org-mode) + (org-make-link-regexps, org-remove-keyword-keys) + (org-get-todo-face, org-export-get-title-from-subtree) + (org-assign-fast-keys, org-get-min-level) + (org-get-wdays, org-clock-find-position) + (org-clock-goto, org-fontify-priorities) + (org-get-date-from-calendar) + (org-entry-add-to-multivalued-property) + (org-entry-remove-from-multivalued-property) + (org-entry-member-in-multivalued-property) + (org-entry-is-todo-p, org-entry-is-done-p, org-get-todo-state) + (org-agenda-get-restriction-and-command) + (org-open-link-from-string, org-columns-open-link) + (org-go-to-remember-target, org-remember-insinuate) + (org-icalendar-cleanup-string, org-first-sibling-p) + (org-back-over-empty-lines, org-skip-whitespace) + (org-goto-local-auto-isearch) + (org-clocktable-steps, org-refile-get-location) + (org-kill-line, org-remove-timestamp-with-keyword) + (org-local-logging): New functions. + (org-agenda-marker-table, org-log-note-how) + (org-goto-local-auto-isearch-map) + (org-last-remember-storage-locations) + (org-imenu-markers, org-agenda-restriction-lock-overlay) + (org-speedbar-restriction-lock-overlay) + (org-massive-special-regexp) + (org-verbatim-re, org-read-date-display-live) + (org-agenda-file-regexp, org-complex-heading-regexp) + (org-completion-fallback-command, org-todo-log-states) + (org-goto-exit-command, org-goto-selected-point) + (org-todo-key-alist, org-todo-key-trigger, org-agenda-remove-date) + (org-agenda-after-show-hook, org-agenda-skip-unavailable-files) + (org-fast-tag-selection-can-set-todo-state, org-local-properties) + (org-store-link-functions, org-columns-top-level-marker) + (orgstruct-mode-map, org-entry-property-inherited-from) + (org-column-overlays, org-current-columns-fmt) + (org-current-columns-maxwidths, org-column-map) + (org-cached-props): New variables. + (org-special-ctrl-k, org-goto-auto-isearch) + (org-agenda-todo-keyword-format) + (org-remember-use-refile-when-interactive) + (org-imenu-depth, org-highlight-latex-fragments-and-specials) + (org-agenda-skip-scheduled-if-done, org-extend-today-until) + (org-agenda-window-frame-fractions, org-fontify-priorities) + (org-agenda-deadline-leaders, org-use-property-inheritance) + (org-clock-into-drawer, org-agenda-compact-blocks) + (org-use-fast-todo-selection, org-fast-tag-selection-include-todo) + (org-edit-timestamp-down-means-later, org-todo-keyword-faces) + (org-agenda-deadline-faces, org-remember-store-without-prompt) + (org-default-columns-format) + (org-agenda-default-appointment-duration) + (org-export-with-footnotes, org-clock-out-when-done) + (org-global-properties, org-todo-keyword-faces) + (org-archive-save-context-info) + (org-edit-timestamp-down-means-later) + (org-scheduled-past-days, org-export-with-drawers) + (org-read-date-prefer-future, org-hide-emphasis-markers) + (org-clock-heading-function, org-clock-in-switch-to-state) + (org-export-with-special-strings): New options. + (org-link-store, org-link-follow, org-latex) + (org-remember-templates, org-time-stamp-rounding-minutes) + (org-back-over-empty-lines, org-find-base-buffer-visiting) + (org-columns-new): Fix typos in docstrings. + (org-ctrl-c-star): Implement a missing branch in the decision + tree. + (org-select-remember-template): Clean the code. + (org-prepare-dblock): Add the extra :content parameter. + (org-write-agenda): New output type ".ics" files. + (org-write-agenda): Call `org-icalendar-verify-function', both for + time stamps and for TODO entries. + (org-export-as-html): Revert the change that killed the html + buffer. Side effects first need to be studied carefully. + (org-get-tags-at): Fix the structure of the condition-case + statement. + (org-ts-regexp0, org-repeat-re, org-display-custom-time) + (org-timestamp-change): Fix regulear expressions to swallow the + extra character for repeat-shift control. + (org-auto-repeat-maybe): Implement the new repeater mechanisms. + (org-get-legal-level): Alias to `org-get-valid-level'. + (org-dblock-write:clocktable): Add a :link parameter, linking + headlines to their location in the Org agenda files. + (org-get-tags-at): Bugfix: prevent `org-back-to-heading' from + throwing an error when getting tags before headlines. + (org-timestamp-change, org-modify-ts-extra) + (org-ts-regexp1): Fix timestamp editing. + (org-agenda-custom-commands-local-options): New constant. + (org-agenda-custom-commands): Use + `org-agenda-custom-commands-local-options' to improve customize + type. "htmlize": Removed hack to fix face problem with htmlize, + it no longer seem necessary. + (org-follow-link-hook): New hook. + (org-agenda-custom-commands): Add "Component" as a tag for each + item in a command serie. + (org-open-at-point): Run `org-follow-link-hook'. + (org-agenda-schedule): Bugfix: don't display marker type when it + is nil. + (org-store-link): org-irc required. + (org-set-regexps-and-options): Parse the new logging options. + (org-todo): Handle the new ways of recording state change stuff. + (org-columns-open-link): Fix bug with opening link in column view. + (org-todo): Make sure that LOGGING properties are honoured. + (org-todo-keywords): Improve docstring. + (org-startup-options): Cleanup startup options. + (org-set-regexps-and-options): Process the "!" markers. + (org-todo): Respect the new logging stuff. + (org-add-log-maybe): New parameter HOW that defines how logging + should be done and also overrides PURPOSE. Add a docstring. + (org-add-log-note): Check if we really need to ask for a note. + (org-get-current-options): Digest the new keyword. + (org-agenda-reset-markers): Rename from + `org-agenda-maybe-reset-markers'. Remove FORCE argument. + (org-diary, org-agenda-quit, org-prepare-agenda): Call the renamed + function, without force argument. + (org-buffer-property-keys): Bind local variables s and p. + (org-make-tags-matcher): Allow "" to match an empty or + non-existent property value. + (org-export-as-html): Join unsorted lists when they directly + follow each other. Such lists may be created by headlines that + are converted to lists. + (org-export-as-html): Use :html-extension instead of + org-export-html-extension. + (org-store-link): Support for links from `rmail-summary-mode'. + (org-columns-new, org-complete, org-set-property): Set the + `include-columns' argument in the call to + `org-buffer-property-keys'. + (org-buffer-property-keys): New argument `include-columns', to + include properties expected by any of the COLUMS formats in the + current buffer. + (org-cleaned-string-for-export): Get rid of drawers first, so that + they will be removed also in the text before the first headline. + (org-clock-report): Show the clocktable when found. + (org-refile): Fix positioning bug when `org-reverse-note-order' is + nil. + (org-version): With prefix argument, insert `org-version' at + point. + (org-agenda-goto): Recenter the window after finding the target + location, to make sure the correct position will be displayed. + (org-agenda-get-deadlines): Don't scale priority with the warning + period. + (org-insert-heading): Don't break line in the middle of the line. + (org-agenda-get-deadlines): Allow `org-deadline-warning-days' to + be 0. + (org-update-checkbox-count): Revamp to deal with hierarchical + beckboxes. This was a patch from Miguel A. Figueroa-Villanueva. + (org-schedule, org-deadline): Use + `org-remove-timestamp-with-keyword' to make sure all such time + stamps are removed. + (org-mode): Support for `align'. + (org-agenda-get-deadlines): Make sure priorities increase as the + due date approaches and is passed. + (org-remember-apply-template): Fix problem with tags that contain + "_" or "@". + (org-make-link-regexps): Improve the regular expression for plain + links. + (org-agenda-get-closed): List each clocking entry. + (org-set-tags): Only tabify before tags if indent-tabs-mode is t. + (org-archive-all-done): Fix incorrect number of stars in regexp. + (org-global-tags-completion-table): Add the value of org-tag-alist + in each buffer, to make sure that also unused tags will be + available for completion. + (org-columns-edit-value) + (org-columns-next-allowed-value): Only update if not in agenda. + (org-dblock-write:clocktable): Call `org-clocktable-steps'. + (org-archive-subtree): Add the outline tree context as a property. + (org-closest-date): New optional argument `prefer'. + (org-goto-map, org-get-location): Implement auto-isearch. + (org-goto-local-search-forward-headings) + (org-get-entries-from-diary): Require diary-lib. + (org-agenda-sunrise-sunset): Require solar. + (org-export-html-style): Doc fix. + (org-get-legal-level): New obsolete alias. + (org-get-valid-level): Rename from `org-get-legal-level'. + (org-promote, org-demote, org-archive-subtree) + (org-remember-handler, org-refile, org-put-clock-overlay): Use it. + (org-info): Use info rather than Info-goto-node. + (org-entry-properties): Let-bind `clocksum'. + (org-unmodified, org-cycle-emulate-tab) + (org-descriptive-links, org-link-file-path-type) + (org-remember-use-refile-when-interactive) + (org-agenda-skip-timestamp-if-done, org-agenda-scheduled-leaders) + (org-export-ascii-bullets, org-agenda-deadline-faces) + (turn-on-orgstruct++, orgtbl-to-texinfo, org-mhe-get-header) + (org-batch-agenda, org-batch-agenda-csv, org-fix-agenda-info) + (org-kill-note-or-show-branches): Fix typos in docstrings. + (org-html-do-expand): `org-export-html-convert-special-strings' + added to the list of conversion. + (org-infile-export-plist, org-get-current-options): Add support + for "-" in the #+OPTION line to let user switch on/off special + strings conversion. + (org-export-plist-vars): New :html-table-tag property. + (org-export-as-html, org-format-org-table-html) + (org-format-table-table-html) Use the :html-table-tag property + instead of the `org-export-html-table-tag' global value. + (org-additional-option-like-keywords): Add "TBLFM". + (org-entry-properties): Include the CLOCKSUM special property. + (org-columns-edit-value): Do not allow to edit the special + CLOCKSUM property. + (org-flag-drawer): Use the original value of `outline-regexp'. + (org-remember-handler): Add invisible-ok flag to call to + `org-end-of-subtree'. + (org-agenda-highlight-todo): Respect + `org-agenda-todo-keyword-format'. + (org-infile-export-plist): No restriction while searching for + options. + (org-remember-handler): Remove comments at the end of the buffer. + (org-table-sort-lines): Make sure sorting works on link + descritions only, and ignores the link. + (org-sort-entries-or-items): Make sure the end of the subtree is + included. + (org-refile-use-outline-path): New allowed values `file' and + `full-file-path'. + (org-get-refile-targets): Respect new values for + `org-refile-use-outline-path'. + (org-agenda-get-restriction-and-command): DEL goes back to initial + list. + (org-export-as-xoxo): Restore point when done. + (org-open-file): Allow multiple %s in command. + (org-get-refile-targets): Interpret the new maxlevel setting. + (org-refile-targets): New option `:maxlevel'. + (org-copy-subtree): Include empty lines before but not after + subtree. + (org-move-item-down, org-move-item-up): Include empty lines before + but not after item. + (org-remember-apply-template): Defaults, completions and history + for template prompts. Also, interpret new `%!' escape. + (org-context-choices): New constant. + (org-bound-and-true-p): New macro. + (org-agenda-restriction-lock): New face. + (org-open-at-point): Remove obsolete way to do redirection in + shell links. + (org-imenu-and-speedbar): New customization group. + (org-entry-properties): Return keyword-less time strings. + (org-clock-in): Use `org-clock-heading-function'. + (org-calendar-holiday): Try to use `calendar-check-holidays' + instead of the obsolete `check-calendar-holidays'. + (org-export-html-special-string-regexps): New constant. + (org-latex-and-export-specials): New face. + (org-link-escape-chars): Use characters instead of strings. + (org-link-escape-chars-browser, org-link-escape) + (org-link-unescape): Use characters instead of strings. + (org-export-html-convert-sub-super, org-html-do-expand): Check for + protected text. + (org-emphasis-alist): Additional `verbatim' flag. + (org-set-emph-re): Handle the verbatim flag and compute + `org-verbatim-re'. + (org-cleaned-string-for-export): Protect verbatim elements. + (org-additional-option-like-keywords): Add new keywords. + (org-get-entry): Rename from `org-get-cleaned-entry'. + (org-agenda-get-scheduled, org-agenda-get-blocks): Use + `org-agenda-skip-scheduled-if-done'. + (org-prepare-agenda-buffers): Allow buffers as arguments. + (org-entry-properties): Add CATEGORY as a special property. + (org-use-property-inheritance): Allow a list of properties as a + value. + (org-eval-in-calendar): No longer update the prompt. + (org-read-date-popup-calendar): Rename from + `org-popup-calendar-for-date-prompt'. + (org-remember-apply-template): Define `remember-finalize' if it is + not yet defined. + (org-read-date): Respect the setting of + `org-read-date-prefer-future'. Use `org-read-date-analyze'. + (org-set-font-lock-defaults): Use `org-archive-tag' instead of a + hardcoded string. + (org-remember-apply-template): Use `remember-finalize' instead of + `remember-buffer'. + (org-columns-compute, org-column-number-to-string) + (org-columns-uncompile-format, org-columns-compile-format) + (org-columns-compile-format): Handle printf format specifier. + (org-columns-new, org-column-number-to-string) + (org-columns-uncompile-format, org-columns-compile-format): + Support for new currency summary type. + (org-tree-to-indirect-buffer): Do not kill old buffer when + `org-indirect-buffer-display' is `new-frame'. + (org-indirect-buffer-display): Document that `new-frame' leads to + indiret buffer proliferation. + (org-agenda-list): Use `org-extend-today-until'. + (org-format-org-table-html): Use lower-case for tag. + (org-agenda-execute): New command. + (org-agenda-mode-map): Keybindings of "g" "G", "e" modified. + (org-remember-apply-template): Use `org-select-remember-template'. + (org-region-active-p): Use `use-region-p'. + (org-cycle-hide-archived-subtrees) + (org-table-rotate-recalc-marks, org-mark-ring-push) + (org-follow-info-link, org-mhe-get-message-folder-from-index) + (org-auto-repeat-maybe, org-store-log-note, org-delete-property) + (org-evaluate-time-range, org-edit-agenda-file-list): + (org-paste-subtree): + (org-calendar-holiday): Use calendar-check-holidays instead of the + obsolete check-calendar-holidays. + (org-table-formula-substitute-names): Remove forgotten temporary + debugging code. + (org-agenda-get-restriction-and-command): Use `mapc' instead of + `mapcar'. + (org-agenda-list): Numeric prefix argument can specify the number + of days. + (remember-register, remember-buffer): Prevent byte compiler from + complaining. + (org-todo): Save and restore match data. + (org-no-warnings): New macro. + (org-columns-eval): Use `org-no-warnings'. + (org-version): Change to 5.13e. + (org-agenda-file-regexp): Fix typo in docstring. + (org-add-planning-info): Fix bug in parenthesis settings. + (org-scan-tags): Catch the case of indirect buffers with no + filename. + (org-fast-tag-selection, org-export-as-ascii, org-export-as-html): + Re-install switch to mapc, had been removed by accident. + (org-columns-map): New binding `C-c C-o'. + (org-columns-menu): Change menu text and added new entry. + (org-columns-eval): Document the use of `next-line'. + (org-columns-follow-link): Remove function. + (org-read-date-get-relative): Fix typo in docstring. + (org-read-date-get-relative): Leading +/- is not optional. + (org-agenda-get-restriction-and-command): Always resize window on + first loop cycle. + (org-agenda-open-link): Make sure the link abbreviations are + present in the agenda buffer. + (org-agenda-files): Allow directories in the variable. + (org-agenda): Use `org-agenda-get-restriction-and-command'. + (org-todo-blocker-hook, org-todo-trigger-hook): New hooks. + (org-remember-apply-template): Catch C-g and make sure window + configuration is restored. + (org-agenda-open-link): Make it work with several links in the + line. + (org-drawers, org-set-regexps-and-options) + (org-get-current-options): Add support for a DRAWERS in-buffer + option. + (org-fit-agenda-window): Use `org-agenda-window-frame-fractions'. + (org-agenda-to-appt): Require calendar. + (org-entry-get-with-inheritance): Widen for search. + (org-columns-display-here): Don't mark buffer as modified when + adding space characters to accomodate column overlays. + (org-export-as-html): Better formatting of tags in the toc. + (org-columns-display-here): Make the ITEM column as compact as + possible. + (org-remember-templates): Customization interface improved. + (org-export-with-property-drawer): Variable removed. + (org-sort-entries): Rewrite using `sort-subr'. + (org-set-property): More appropriate completion during interactive + use. + (org-sort-entries): Allow sorting by property. + (org-additional-option-like-keywords): Add more values. + (org-sort-entries-or-items): Rename from `org-sort-entries'. + (org-at-timestamp-p, org-timestamp-change) + (org-remember-templates): First element of each entry is now a + name for the template. + (org-store-log-note): Check for `org-note-abort'. + (org-kill-note-or-show-branches): New command. + (org-cut-subtree, org-copy-subtree): New argument N to act on N + sequential subtrees. + (org-paste-subtree): Fix the level at which a tree is pasted. + (org-fit-agenda-window): Limitations on window size removed. + (org-agenda-find-same-or-today-or-agenda): Rename from + `org-agenda-find-today-or-agenda'. + (org-agenda-scheduled-leaders) + (org-agenda-get-deadlines): Use `org-agenda-deadline-leaders'. + (org-agenda-get-scheduled): Use `org-agenda-scheduled-leaders'. + (org-export-with-tags, org-export-plist-vars) + (org-infile-export-plist): New "tags" option. + (org-cached-entry-get): Use `org-use-property-inheritance'. + (org-remember-apply-template): Fix typo. + (org-additional-option-like-keywords): New constant. + (org-complete): Use `org-additional-option-like-keywords'. + (org-clock-report): Only update the table at point, or insert a + new one. + (org-open-file): Use `start-process-shell-command' instead of + `shell-command' with an ampersand. + (org-deadline, org-schedule): New argument REMOVE to remove the + date from the entry. + (org-agenda-schedule, org-agenda-deadline): Pass the prefix + argument to `org-schedule' and `org-deadline'. + (org-trim): Use the correct expressions for beginning and end of + the string. + (org-get-cleaned-entry): Trim the string before returning it. + (org-agenda-tags-column): Rename from + `org-agenda-align-tags-to-column'. + (org-agenda-align-tags): Allow negative values for + `org-agenda-tags-column'. + (org-insert-labeled-timestamps-before-properties-drawer): Remove + var. + (org-agenda-to-appt): New optional argument FILTER. + (org-complete): Use `org-completion-fallback-command'. + (org-find-base-buffer-visiting): Catch the case that there is no + buffer visiting the file. + (org-todo): Use `org-property-or-variable-value' + (org-prepare-agenda, org-agenda-list): Use + `org-agenda-compact-blocks'. + (org-agenda-schedule, org-agenda-deadline): Call + `org-agenda-show-new-time'. + (org-agenda-show-new-time): New argument PREFIX. + (org-colgroup-info-to-vline-list): Fix but that cause a shift in + the vertical lines. + (org-buffer-property-keys): New argument INCLUDE-DEFAULTS. + (org-maybe-renumber-ordered-list, org-cycle-list-bullet) + (org-indent-item): No arg in call to `org-fix-bullet-type'. + (org-fix-bullet-type): Remove argument. + (org-read-date): Check for am/pm twice, to catch the end time. + (org-goto-map): Use `suppress-keymap'. + (org-remember-apply-template): Respect the dynamically scoped + selection character. + (org-kill-is-subtree-p): Use `org-outline-regexp'. + (org-outline-regexp): New constant. + (org-remember-handler): Throw error when the target file is not in + org-mode. + (org-cleaned-string-for-export): No longer call + `org-export-latex-cleaned-string' with an argument. + (org-get-tags): Returns now a list, not a string. + (org-archive-subtree): No need to split return of `org-get-tags'. + (org-set-tags, org-entry-properties): Call `org-get-tags-string' + instead of `org-get-tags'. + (org-agenda-format-date): Rename from `org-agenda-date-format'. + (org-time-from-absolute, org-agenda-format-date-aligned): New + funs. + (org-compatible-face): New argument INHERITS. Inherit from this + face if possible. + (org-level-1, org-level-2, org-level-3, org-level-4) + (org-level-5, org-level-6, org-level-7, org-level-8) + (org-special-keyword, org-drawer, org-column, org-warning) + (org-archived, org-todo, org-done, org-headline-done, org-table) + (org-formula, org-code, org-agenda-structure) + (org-scheduled-today, org-scheduled-previously) + (org-upcoming-deadline, org-time-grid): Call `org-compatible-face' + in the new way. + (org-get-heading): New argument NO-TAGS. + (org-fast-tag-selection-include-todo): Made defvar instead of + defcustom, feature is not deprecated. + (org-remember-store-without-prompt): New default value t. + (org-set-regexps-and-options): #+TODO is an alias for SEQ_TODO. + Compute the log states. + (org-goto-map): More commands copied from global map. Also bind + `org-occur'. + (org-goto): Made into a general lookup command. + (org-get-location): Complete rewrite. + (org-goto-ret, org-goto-left, org-goto-right, org-goto-quit): Set + the new variables. + (org-paste-subtree): Whitespace insertion strategy revised. + (org-remember-apply-template): Protect v-A from the possibility + that v-a might be nil. + (org-remember-handler): Insertion rules revised. + (org-todo): Respect org-todo-log-states. + (org-entry-get-with-inheritance): Use `org-up-heading-safe'. + (org-confirm-shell-link-function) + (org-confirm-elisp-link-function): Doc fixes. + (org-re): Also replace the :alpha: class. + (org-todo-tag-alist): Variable removed. + (org-log-done): Docstring fixed. + (org-deadline-warning-days): New default value 14. + (org-tag-alist): Docstring fixed. + (org-export-language-setup): New languages added. + (org-set-regexps-and-options): Compute the new variables. + (org-paste-subtree): Cleaning up. + (org-remember-apply-template): New escape %A. + (org-todo): Call fast TODO selection. + (org-add-log-note): Allow prefix for abort exit. + (org-at-property-p, org-entry-properties) + (org-columns-get-autowidth-alist): Use :alpha: class. + (org-agenda-get-deadlines): Use `org-get-wdays'. + (org-agenda-get-deadlines): Reverse ee before returning. + (org-format-agenda-item): New argument REMOVE-RE. + (org-agenda-convert-date): Baha'i calendar added. + (org-infile-export-plist): Also find DATE line. + (org-export-as-html, org-export-as-ascii): Use the date format. + (org-shiftup, org-shiftdown): Use. + `org-edit-timestamp-down-means-later'. + (org-columns-compile-format) + (org-columns-get-autowidth-alist, org-buffer-property-keys) + (org-entry-properties, org-at-property-p): Allow [:alnum:] in + property names. + (org-export-visible): Fix drawers before export. + (org-do-sort): Allow sorting by priority. + (org-agenda-files): Ignore non-existing files. + (org-ellipsis): All a face as value. + (org-mode): Interprete the face value of `org-ellipsis'. + (org-archive-subtree): Store context info in archived entry. + (org-fast-tag-selection): Allow setting TODO states through this + interface. + (org-cycle): Docstring updated. + (org-set-font-lock-defaults, org-agenda-highlight-todo): Use + `org-get-todo-face'. + (org-table-edit-field, org-table-show-reference) + (org-table-edit-formulas, org-add-log-note) + (org-fast-tag-selection, org-agenda, org-prepare-agenda) + (org-timeline): Use `org-switch-to-buffer-other-window' instead of + `switch-to-buffer-other-window' to make sure that the temporary + windows show up on the current frame. + (org-mhe-get-message-real-folder, org-batch-store-agenda-views) + (org-get-entries-from-diary, org-replace-region-by-html): Don't + allow pop-up frames. + (org-agenda-get-deadlines, org-agenda-get-scheduled): Fix problems + with time-of-day. + (org-agenda-get-scheduled, org-agenda-get-deadlines): Fix problems + with listing items that are DONE. + (org-change-tag-in-region): New command. + (org-agenda-skip-scheduled-if-done) + (org-agenda-skip-deadline-if-done): Docstring clarified. + (org-mode): Hide drawers on startup. + (org-set-regexps-and-options): Use `org-remove-keyword-keys'. + (org-agenda-skip): Allow a form for `org-agenda-skip-function'. + (org-agenda-redo): Re-use local settings. + (org-agenda): Store local settings. + (org-agenda-get-deadlines, org-agenda-get-scheduled): Also handle + entries on their due date. + (org-agenda-get-timestamps): No longer handle the due dates of + schedules and deadline items. + (org-insert-link-global, org-open-at-point-global): New commands. + (org-export-as-ascii): Call `org-cleaned-string-for-export' with a + :for-ascii parameter. + (org-skip-comments): Function removed. + (org-cleaned-string-for-export): Handle special table lines. + (org-entry-get-with-inheritance): Check global properties. + (org-set-regexps-and-options): Find the #+PROPERTY line. + (org-link-types): Change type into variable (was constant). + (org-link-re-with-space, org-link-re-with-space2) + (org-angle-link-re, org-plain-link-re, org-bracket-link-regexp) + (org-bracket-link-analytic-regexp, org-any-link-re): Creation of + these regular expressions happens now in the function + `org-make-link-regexps'. + (org-store-link): Call the functions in + `org-store-link-functions'. + (org-activate-tags): Force matches to be in headlines. + (org-batch-store-agenda-views): Fix bug with killing agenda + buffer. + (org-columns-display-here): Make sure this works in a narrowed + buffer by checking for point-min. + (org-columns-display-here): Make the rest of the line intangible, + so that point never can be there. + (org-cleaned-string-for-export): Use `with-current-buffer'. + (org-replace-region-by-html): Use `with-current-buffer'. + (org-unfontify-region, org-do-occur, org-columns-display-here) + (org-columns-remove-overlays, org-columns-quit) + (org-columns-edit-value, org-columns-next-allowed-value) + (org-eval-in-calendar, org-agenda-undo, org-no-read-only) + (org-finalize-agenda, org-remove-subtree-entries-from-agenda) + (org-agenda-todo, org-agenda-change-all-lines) + (org-agenda-align-tags, org-agenda-priority) + (org-agenda-set-tags, org-agenda-toggle-archive-tag) + (org-agenda-show-new-time, org-cleaned-string-for-export) + (org-export-grab-title-from-buffer) + (org-export-as-ascii, org-export-as-html): Use `inhibit-read-only' + instead of `buffer-read-only'. + (org-export-as-html): Set `coding-system-for-write'. + (org-archive-subtree): Fixed bug with modifying TODO keyword. + (org-beginning-of-line): Also treat C-a special in items. + (org-table-convert-refs-to-rc): Fixed problem with column + reference after "..". + (org-columns-compute): Don't mark buffer modified because of text + properties. + (org-batch-store-agenda-views): Use the variable + `default-directory', not the function. + (org-clock-out-if-current): Respect `org-clock-out-when-done'. + (org-html-entities): Added HTML entities for smileys. + (org-end-of-line): Move to end of line if in headline without + tags. + (org-agenda-day-view, org-agenda-week-view): Remember span as + default. + (org-columns-edit-value): Rename from `org-column-edit'. + (org-columns-display-here-title): Rename from + `org-overlay-columns-title'. + (org-columns-remove-overlays): Rename from + org-remove-column-overlays. + (org-columns-get-autowidth-alist): Rename from + `org-get-columns-autowidth-alist'. + (org-columns-display-here): Rename from `org-overlay-columns'. + (org-columns-new-overlay): Rename from `org-new-column-overlay'. + (org-columns-quit): Rename from `org-column-quit'. + (org-columns-show-value): Rename from `org-column-show-value'. + (org-columns-current-fmt): Rename from `org-current-columns-fmt'. + (org-columns-overlays): Rename from `org-column-overlays'. + (org-columns-map): Rename from `org-column-map'. + (org-columns-current-maxwidths): Rename from + `org-current-columns-maxwidths'. + (org-columns-begin-marker, org-columns-current-fmt-compiled) + (org-previous-header-line-format) + (org-columns-inhibit-recalculation) + (org-columns-default-format): Rename from + `org-default-columns-format'. + (org-property-re): New constant. + (orgstruct-mode): New minor mode. + (org-cycle-list-bullet): New command. + (org-special-properties, org-property-start-re) + (org-property-end-re): New constants. + (org-with-point-at): New macro. + (org-insert-property-drawer): New command. + (org-column): New face. + (org-column-menu): New menu. + (org-columns, org-agenda-columns): New commands. + (org-properties): New customize group. + (org-priority): Realign tags after changing priority. + (org-preserve-lc): New macro. + (org-update-checkbox-count): Catch case when there is no headline. + (org-agenda-quit): Remove any column overlays. + (org-beginning-of-item-list): Fixed bug when non-item line is + indented too deep. + (org-make-tags-matcher): Handle property matches. + (org-table-recalculate): Swap evaluation order: Field formula + first, then column formulas, but don't allow them to overwrite the + field formulas. + (org-table-eval-formula): New argument untouchable. + (org-export-as-html): Fix replacement bug for XEmacs. 2008-04-06 Chong Yidong From c41e38e771e589f3a4b2ae18c1d691af9c22755e Mon Sep 17 00:00:00 2001 From: Carsten Dominik Date: Tue, 8 Apr 2008 07:47:25 +0000 Subject: [PATCH 23/56] * textmodes/org-export-latex.el: New file. * textmodes/org-irc.el: New file. * textmodes/org-mac-message.el: New file. * textmodes/org-publish.el: New file. * textmodes/org.el (org-agenda-collect-markers) (org-create-marker-find-array) (org-check-agenda-marker-table, org-extract-log-state-settings) (org-nofm-to-completion, org-refile-goto-last-stored) (org-export-html-convert-special-strings, org-first-list-item-p) (org-imenu-new-marker, org-imenu-get-tree) (org-speedbar-set-agenda-restriction) (org-agenda-set-restriction-lock) (org-agenda-remove-restriction-lock) (org-agenda-maybe-redo, org-compute-latex-and-specials-regexp) (org-do-latex-and-special-faces, org-read-date-display) (org-select-remember-template, org-agenda-copy-local-variable) (org-read-date-get-relative, org-columns-cleanup-item) (org-find-entry-with-id) (org-insert-columns-dblock, org-listtable-to-string) (org-dblock-write:columnview, org-columns-capture-view) (org-edit-headline, org-parse-local-options) (org-in-clocktable-p, org-property-or-variable-value) (org-get-tags-string, org-up-heading-safe) (org-fast-todo-selection, org-get-wdays) (org-switch-to-buffer-other-window, org-agenda-deadline-face) (org-add-link-type, org-columns-content, org-columns-widen) (org-columns-next-allowed-value, org-columns-edit-allowed) (org-columns-store-format) (org-columns-uncompile-format, org-columns-redo) (org-columns-edit-attributes, org-delete-property) (org-set-property, org-columns-update, org-columns-compute) (org-columns-eval) (org-columns-not-in-agenda, org-columns-compute-all) (org-property-next-allowed-value) (org-columns-compile-format, org-fill-paragraph-experimental) (org-string-to-number, org-property-action, org-columns-move-left) (org-columns-new) (org-column-number-to-string, org-property-previous-allowed-value) (org-at-property-p, org-columns-delete) (org-columns-previous-allowed-value) (org-columns-move-right, org-columns-narrow) (org-property-get-allowed-values) (org-verify-version, org-column-string-to-number) (org-delete-property-globally) (org-get-property-block, org-entry-properties, org-entry-get) (org-entry-delete, org-entry-get-with-inheritance) (org-entry-put, org-buffer-property-keys, org-new-column-overlay) (org-overlay-columns) (org-overlay-columns-title, org-remove-column-overlays) (org-column-show-value, org-column-quit, org-column-edit) (org-cached-entry-get, org-table-put-field-property) (org-get-columns-autowidth-alist, turn-on-orgstruct) (orgstruct-error, orgstruct-setup) (orgstruct-make-binding, org-context-p, org-get-local-variables) (org-run-like-in-org-mode) (org-make-link-regexps, org-remove-keyword-keys) (org-get-todo-face, org-export-get-title-from-subtree) (org-assign-fast-keys, org-get-min-level) (org-get-wdays, org-clock-find-position) (org-clock-goto, org-fontify-priorities) (org-get-date-from-calendar) (org-entry-add-to-multivalued-property) (org-entry-remove-from-multivalued-property) (org-entry-member-in-multivalued-property) (org-entry-is-todo-p, org-entry-is-done-p, org-get-todo-state) (org-agenda-get-restriction-and-command) (org-open-link-from-string, org-columns-open-link) (org-go-to-remember-target, org-remember-insinuate) (org-icalendar-cleanup-string, org-first-sibling-p) (org-back-over-empty-lines, org-skip-whitespace) (org-goto-local-auto-isearch) (org-clocktable-steps, org-refile-get-location) (org-kill-line, org-remove-timestamp-with-keyword) (org-local-logging): New functions. (org-agenda-marker-table, org-log-note-how) (org-goto-local-auto-isearch-map) (org-last-remember-storage-locations) (org-imenu-markers, org-agenda-restriction-lock-overlay) (org-speedbar-restriction-lock-overlay) (org-massive-special-regexp) (org-verbatim-re, org-read-date-display-live) (org-agenda-file-regexp, org-complex-heading-regexp) (org-completion-fallback-command, org-todo-log-states) (org-goto-exit-command, org-goto-selected-point) (org-todo-key-alist, org-todo-key-trigger, org-agenda-remove-date) (org-agenda-after-show-hook, org-agenda-skip-unavailable-files) (org-fast-tag-selection-can-set-todo-state, org-local-properties) (org-store-link-functions, org-columns-top-level-marker) (orgstruct-mode-map, org-entry-property-inherited-from) (org-column-overlays, org-current-columns-fmt) (org-current-columns-maxwidths, org-column-map) (org-cached-props): New variables. (org-special-ctrl-k, org-goto-auto-isearch) (org-agenda-todo-keyword-format) (org-remember-use-refile-when-interactive) (org-imenu-depth, org-highlight-latex-fragments-and-specials) (org-agenda-skip-scheduled-if-done, org-extend-today-until) (org-agenda-window-frame-fractions, org-fontify-priorities) (org-agenda-deadline-leaders, org-use-property-inheritance) (org-clock-into-drawer, org-agenda-compact-blocks) (org-use-fast-todo-selection, org-fast-tag-selection-include-todo) (org-edit-timestamp-down-means-later, org-todo-keyword-faces) (org-agenda-deadline-faces, org-remember-store-without-prompt) (org-default-columns-format) (org-agenda-default-appointment-duration) (org-export-with-footnotes, org-clock-out-when-done) (org-global-properties, org-todo-keyword-faces) (org-archive-save-context-info) (org-edit-timestamp-down-means-later) (org-scheduled-past-days, org-export-with-drawers) (org-read-date-prefer-future, org-hide-emphasis-markers) (org-clock-heading-function, org-clock-in-switch-to-state) (org-export-with-special-strings): New options. (org-link-store, org-link-follow, org-latex) (org-remember-templates, org-time-stamp-rounding-minutes) (org-back-over-empty-lines, org-find-base-buffer-visiting) (org-columns-new): Fix typos in docstrings. (org-ctrl-c-star): Implement a missing branch in the decision tree. (org-select-remember-template): Clean the code. (org-prepare-dblock): Add the extra :content parameter. (org-write-agenda): New output type ".ics" files. (org-write-agenda): Call `org-icalendar-verify-function', both for time stamps and for TODO entries. (org-export-as-html): Revert the change that killed the html buffer. Side effects first need to be studied carefully. (org-get-tags-at): Fix the structure of the condition-case statement. (org-ts-regexp0, org-repeat-re, org-display-custom-time) (org-timestamp-change): Fix regulear expressions to swallow the extra character for repeat-shift control. (org-auto-repeat-maybe): Implement the new repeater mechanisms. (org-get-legal-level): Alias to `org-get-valid-level'. (org-dblock-write:clocktable): Add a :link parameter, linking headlines to their location in the Org agenda files. (org-get-tags-at): Bugfix: prevent `org-back-to-heading' from throwing an error when getting tags before headlines. (org-timestamp-change, org-modify-ts-extra) (org-ts-regexp1): Fix timestamp editing. (org-agenda-custom-commands-local-options): New constant. (org-agenda-custom-commands): Use `org-agenda-custom-commands-local-options' to improve customize type. "htmlize": Removed hack to fix face problem with htmlize, it no longer seem necessary. (org-follow-link-hook): New hook. (org-agenda-custom-commands): Add "Component" as a tag for each item in a command serie. (org-open-at-point): Run `org-follow-link-hook'. (org-agenda-schedule): Bugfix: don't display marker type when it is nil. (org-store-link): org-irc required. (org-set-regexps-and-options): Parse the new logging options. (org-todo): Handle the new ways of recording state change stuff. (org-columns-open-link): Fix bug with opening link in column view. (org-todo): Make sure that LOGGING properties are honoured. (org-todo-keywords): Improve docstring. (org-startup-options): Cleanup startup options. (org-set-regexps-and-options): Process the "!" markers. (org-todo): Respect the new logging stuff. (org-add-log-maybe): New parameter HOW that defines how logging should be done and also overrides PURPOSE. Add a docstring. (org-add-log-note): Check if we really need to ask for a note. (org-get-current-options): Digest the new keyword. (org-agenda-reset-markers): Rename from `org-agenda-maybe-reset-markers'. Remove FORCE argument. (org-diary, org-agenda-quit, org-prepare-agenda): Call the renamed function, without force argument. (org-buffer-property-keys): Bind local variables s and p. (org-make-tags-matcher): Allow "" to match an empty or non-existent property value. (org-export-as-html): Join unsorted lists when they directly follow each other. Such lists may be created by headlines that are converted to lists. (org-export-as-html): Use :html-extension instead of org-export-html-extension. (org-store-link): Support for links from `rmail-summary-mode'. (org-columns-new, org-complete, org-set-property): Set the `include-columns' argument in the call to `org-buffer-property-keys'. (org-buffer-property-keys): New argument `include-columns', to include properties expected by any of the COLUMS formats in the current buffer. (org-cleaned-string-for-export): Get rid of drawers first, so that they will be removed also in the text before the first headline. (org-clock-report): Show the clocktable when found. (org-refile): Fix positioning bug when `org-reverse-note-order' is nil. (org-version): With prefix argument, insert `org-version' at point. (org-agenda-goto): Recenter the window after finding the target location, to make sure the correct position will be displayed. (org-agenda-get-deadlines): Don't scale priority with the warning period. (org-insert-heading): Don't break line in the middle of the line. (org-agenda-get-deadlines): Allow `org-deadline-warning-days' to be 0. (org-update-checkbox-count): Revamp to deal with hierarchical beckboxes. This was a patch from Miguel A. Figueroa-Villanueva. (org-schedule, org-deadline): Use `org-remove-timestamp-with-keyword' to make sure all such time stamps are removed. (org-mode): Support for `align'. (org-agenda-get-deadlines): Make sure priorities increase as the due date approaches and is passed. (org-remember-apply-template): Fix problem with tags that contain "_" or "@". (org-make-link-regexps): Improve the regular expression for plain links. (org-agenda-get-closed): List each clocking entry. (org-set-tags): Only tabify before tags if indent-tabs-mode is t. (org-archive-all-done): Fix incorrect number of stars in regexp. (org-global-tags-completion-table): Add the value of org-tag-alist in each buffer, to make sure that also unused tags will be available for completion. (org-columns-edit-value) (org-columns-next-allowed-value): Only update if not in agenda. (org-dblock-write:clocktable): Call `org-clocktable-steps'. (org-archive-subtree): Add the outline tree context as a property. (org-closest-date): New optional argument `prefer'. (org-goto-map, org-get-location): Implement auto-isearch. (org-goto-local-search-forward-headings) (org-get-entries-from-diary): Require diary-lib. (org-agenda-sunrise-sunset): Require solar. (org-export-html-style): Doc fix. (org-get-legal-level): New obsolete alias. (org-get-valid-level): Rename from `org-get-legal-level'. (org-promote, org-demote, org-archive-subtree) (org-remember-handler, org-refile, org-put-clock-overlay): Use it. (org-info): Use info rather than Info-goto-node. (org-entry-properties): Let-bind `clocksum'. (org-unmodified, org-cycle-emulate-tab) (org-descriptive-links, org-link-file-path-type) (org-remember-use-refile-when-interactive) (org-agenda-skip-timestamp-if-done, org-agenda-scheduled-leaders) (org-export-ascii-bullets, org-agenda-deadline-faces) (turn-on-orgstruct++, orgtbl-to-texinfo, org-mhe-get-header) (org-batch-agenda, org-batch-agenda-csv, org-fix-agenda-info) (org-kill-note-or-show-branches): Fix typos in docstrings. (org-html-do-expand): `org-export-html-convert-special-strings' added to the list of conversion. (org-infile-export-plist, org-get-current-options): Add support for "-" in the #+OPTION line to let user switch on/off special strings conversion. (org-export-plist-vars): New :html-table-tag property. (org-export-as-html, org-format-org-table-html) (org-format-table-table-html) Use the :html-table-tag property instead of the `org-export-html-table-tag' global value. (org-additional-option-like-keywords): Add "TBLFM". (org-entry-properties): Include the CLOCKSUM special property. (org-columns-edit-value): Do not allow to edit the special CLOCKSUM property. (org-flag-drawer): Use the original value of `outline-regexp'. (org-remember-handler): Add invisible-ok flag to call to `org-end-of-subtree'. (org-agenda-highlight-todo): Respect `org-agenda-todo-keyword-format'. (org-infile-export-plist): No restriction while searching for options. (org-remember-handler): Remove comments at the end of the buffer. (org-table-sort-lines): Make sure sorting works on link descritions only, and ignores the link. (org-sort-entries-or-items): Make sure the end of the subtree is included. (org-refile-use-outline-path): New allowed values `file' and `full-file-path'. (org-get-refile-targets): Respect new values for `org-refile-use-outline-path'. (org-agenda-get-restriction-and-command): DEL goes back to initial list. (org-export-as-xoxo): Restore point when done. (org-open-file): Allow multiple %s in command. (org-get-refile-targets): Interpret the new maxlevel setting. (org-refile-targets): New option `:maxlevel'. (org-copy-subtree): Include empty lines before but not after subtree. (org-move-item-down, org-move-item-up): Include empty lines before but not after item. (org-remember-apply-template): Defaults, completions and history for template prompts. Also, interpret new `%!' escape. (org-context-choices): New constant. (org-bound-and-true-p): New macro. (org-agenda-restriction-lock): New face. (org-open-at-point): Remove obsolete way to do redirection in shell links. (org-imenu-and-speedbar): New customization group. (org-entry-properties): Return keyword-less time strings. (org-clock-in): Use `org-clock-heading-function'. (org-calendar-holiday): Try to use `calendar-check-holidays' instead of the obsolete `check-calendar-holidays'. (org-export-html-special-string-regexps): New constant. (org-latex-and-export-specials): New face. (org-link-escape-chars): Use characters instead of strings. (org-link-escape-chars-browser, org-link-escape) (org-link-unescape): Use characters instead of strings. (org-export-html-convert-sub-super, org-html-do-expand): Check for protected text. (org-emphasis-alist): Additional `verbatim' flag. (org-set-emph-re): Handle the verbatim flag and compute `org-verbatim-re'. (org-cleaned-string-for-export): Protect verbatim elements. (org-additional-option-like-keywords): Add new keywords. (org-get-entry): Rename from `org-get-cleaned-entry'. (org-agenda-get-scheduled, org-agenda-get-blocks): Use `org-agenda-skip-scheduled-if-done'. (org-prepare-agenda-buffers): Allow buffers as arguments. (org-entry-properties): Add CATEGORY as a special property. (org-use-property-inheritance): Allow a list of properties as a value. (org-eval-in-calendar): No longer update the prompt. (org-read-date-popup-calendar): Rename from `org-popup-calendar-for-date-prompt'. (org-remember-apply-template): Define `remember-finalize' if it is not yet defined. (org-read-date): Respect the setting of `org-read-date-prefer-future'. Use `org-read-date-analyze'. (org-set-font-lock-defaults): Use `org-archive-tag' instead of a hardcoded string. (org-remember-apply-template): Use `remember-finalize' instead of `remember-buffer'. (org-columns-compute, org-column-number-to-string) (org-columns-uncompile-format, org-columns-compile-format) (org-columns-compile-format): Handle printf format specifier. (org-columns-new, org-column-number-to-string) (org-columns-uncompile-format, org-columns-compile-format): Support for new currency summary type. (org-tree-to-indirect-buffer): Do not kill old buffer when `org-indirect-buffer-display' is `new-frame'. (org-indirect-buffer-display): Document that `new-frame' leads to indiret buffer proliferation. (org-agenda-list): Use `org-extend-today-until'. (org-format-org-table-html): Use lower-case for tag. (org-agenda-execute): New command. (org-agenda-mode-map): Keybindings of "g" "G", "e" modified. (org-remember-apply-template): Use `org-select-remember-template'. (org-region-active-p): Use `use-region-p'. (org-cycle-hide-archived-subtrees) (org-table-rotate-recalc-marks, org-mark-ring-push) (org-follow-info-link, org-mhe-get-message-folder-from-index) (org-auto-repeat-maybe, org-store-log-note, org-delete-property) (org-evaluate-time-range, org-edit-agenda-file-list): (org-paste-subtree): (org-calendar-holiday): Use calendar-check-holidays instead of the obsolete check-calendar-holidays. (org-table-formula-substitute-names): Remove forgotten temporary debugging code. (org-agenda-get-restriction-and-command): Use `mapc' instead of `mapcar'. (org-agenda-list): Numeric prefix argument can specify the number of days. (remember-register, remember-buffer): Prevent byte compiler from complaining. (org-todo): Save and restore match data. (org-no-warnings): New macro. (org-columns-eval): Use `org-no-warnings'. (org-version): Change to 5.13e. (org-agenda-file-regexp): Fix typo in docstring. (org-add-planning-info): Fix bug in parenthesis settings. (org-scan-tags): Catch the case of indirect buffers with no filename. (org-fast-tag-selection, org-export-as-ascii, org-export-as-html): Re-install switch to mapc, had been removed by accident. (org-columns-map): New binding `C-c C-o'. (org-columns-menu): Change menu text and added new entry. (org-columns-eval): Document the use of `next-line'. (org-columns-follow-link): Remove function. (org-read-date-get-relative): Fix typo in docstring. (org-read-date-get-relative): Leading +/- is not optional. (org-agenda-get-restriction-and-command): Always resize window on first loop cycle. (org-agenda-open-link): Make sure the link abbreviations are present in the agenda buffer. (org-agenda-files): Allow directories in the variable. (org-agenda): Use `org-agenda-get-restriction-and-command'. (org-todo-blocker-hook, org-todo-trigger-hook): New hooks. (org-remember-apply-template): Catch C-g and make sure window configuration is restored. (org-agenda-open-link): Make it work with several links in the line. (org-drawers, org-set-regexps-and-options) (org-get-current-options): Add support for a DRAWERS in-buffer option. (org-fit-agenda-window): Use `org-agenda-window-frame-fractions'. (org-agenda-to-appt): Require calendar. (org-entry-get-with-inheritance): Widen for search. (org-columns-display-here): Don't mark buffer as modified when adding space characters to accomodate column overlays. (org-export-as-html): Better formatting of tags in the toc. (org-columns-display-here): Make the ITEM column as compact as possible. (org-remember-templates): Customization interface improved. (org-export-with-property-drawer): Variable removed. (org-sort-entries): Rewrite using `sort-subr'. (org-set-property): More appropriate completion during interactive use. (org-sort-entries): Allow sorting by property. (org-additional-option-like-keywords): Add more values. (org-sort-entries-or-items): Rename from `org-sort-entries'. (org-at-timestamp-p, org-timestamp-change) (org-remember-templates): First element of each entry is now a name for the template. (org-store-log-note): Check for `org-note-abort'. (org-kill-note-or-show-branches): New command. (org-cut-subtree, org-copy-subtree): New argument N to act on N sequential subtrees. (org-paste-subtree): Fix the level at which a tree is pasted. (org-fit-agenda-window): Limitations on window size removed. (org-agenda-find-same-or-today-or-agenda): Rename from `org-agenda-find-today-or-agenda'. (org-agenda-scheduled-leaders) (org-agenda-get-deadlines): Use `org-agenda-deadline-leaders'. (org-agenda-get-scheduled): Use `org-agenda-scheduled-leaders'. (org-export-with-tags, org-export-plist-vars) (org-infile-export-plist): New "tags" option. (org-cached-entry-get): Use `org-use-property-inheritance'. (org-remember-apply-template): Fix typo. (org-additional-option-like-keywords): New constant. (org-complete): Use `org-additional-option-like-keywords'. (org-clock-report): Only update the table at point, or insert a new one. (org-open-file): Use `start-process-shell-command' instead of `shell-command' with an ampersand. (org-deadline, org-schedule): New argument REMOVE to remove the date from the entry. (org-agenda-schedule, org-agenda-deadline): Pass the prefix argument to `org-schedule' and `org-deadline'. (org-trim): Use the correct expressions for beginning and end of the string. (org-get-cleaned-entry): Trim the string before returning it. (org-agenda-tags-column): Rename from `org-agenda-align-tags-to-column'. (org-agenda-align-tags): Allow negative values for `org-agenda-tags-column'. (org-insert-labeled-timestamps-before-properties-drawer): Remove var. (org-agenda-to-appt): New optional argument FILTER. (org-complete): Use `org-completion-fallback-command'. (org-find-base-buffer-visiting): Catch the case that there is no buffer visiting the file. (org-todo): Use `org-property-or-variable-value' (org-prepare-agenda, org-agenda-list): Use `org-agenda-compact-blocks'. (org-agenda-schedule, org-agenda-deadline): Call `org-agenda-show-new-time'. (org-agenda-show-new-time): New argument PREFIX. (org-colgroup-info-to-vline-list): Fix but that cause a shift in the vertical lines. (org-buffer-property-keys): New argument INCLUDE-DEFAULTS. (org-maybe-renumber-ordered-list, org-cycle-list-bullet) (org-indent-item): No arg in call to `org-fix-bullet-type'. (org-fix-bullet-type): Remove argument. (org-read-date): Check for am/pm twice, to catch the end time. (org-goto-map): Use `suppress-keymap'. (org-remember-apply-template): Respect the dynamically scoped selection character. (org-kill-is-subtree-p): Use `org-outline-regexp'. (org-outline-regexp): New constant. (org-remember-handler): Throw error when the target file is not in org-mode. (org-cleaned-string-for-export): No longer call `org-export-latex-cleaned-string' with an argument. (org-get-tags): Returns now a list, not a string. (org-archive-subtree): No need to split return of `org-get-tags'. (org-set-tags, org-entry-properties): Call `org-get-tags-string' instead of `org-get-tags'. (org-agenda-format-date): Rename from `org-agenda-date-format'. (org-time-from-absolute, org-agenda-format-date-aligned): New funs. (org-compatible-face): New argument INHERITS. Inherit from this face if possible. (org-level-1, org-level-2, org-level-3, org-level-4) (org-level-5, org-level-6, org-level-7, org-level-8) (org-special-keyword, org-drawer, org-column, org-warning) (org-archived, org-todo, org-done, org-headline-done, org-table) (org-formula, org-code, org-agenda-structure) (org-scheduled-today, org-scheduled-previously) (org-upcoming-deadline, org-time-grid): Call `org-compatible-face' in the new way. (org-get-heading): New argument NO-TAGS. (org-fast-tag-selection-include-todo): Made defvar instead of defcustom, feature is not deprecated. (org-remember-store-without-prompt): New default value t. (org-set-regexps-and-options): #+TODO is an alias for SEQ_TODO. Compute the log states. (org-goto-map): More commands copied from global map. Also bind `org-occur'. (org-goto): Made into a general lookup command. (org-get-location): Complete rewrite. (org-goto-ret, org-goto-left, org-goto-right, org-goto-quit): Set the new variables. (org-paste-subtree): Whitespace insertion strategy revised. (org-remember-apply-template): Protect v-A from the possibility that v-a might be nil. (org-remember-handler): Insertion rules revised. (org-todo): Respect org-todo-log-states. (org-entry-get-with-inheritance): Use `org-up-heading-safe'. (org-confirm-shell-link-function) (org-confirm-elisp-link-function): Doc fixes. (org-re): Also replace the :alpha: class. (org-todo-tag-alist): Variable removed. (org-log-done): Docstring fixed. (org-deadline-warning-days): New default value 14. (org-tag-alist): Docstring fixed. (org-export-language-setup): New languages added. (org-set-regexps-and-options): Compute the new variables. (org-paste-subtree): Cleaning up. (org-remember-apply-template): New escape %A. (org-todo): Call fast TODO selection. (org-add-log-note): Allow prefix for abort exit. (org-at-property-p, org-entry-properties) (org-columns-get-autowidth-alist): Use :alpha: class. (org-agenda-get-deadlines): Use `org-get-wdays'. (org-agenda-get-deadlines): Reverse ee before returning. (org-format-agenda-item): New argument REMOVE-RE. (org-agenda-convert-date): Baha'i calendar added. (org-infile-export-plist): Also find DATE line. (org-export-as-html, org-export-as-ascii): Use the date format. (org-shiftup, org-shiftdown): Use. `org-edit-timestamp-down-means-later'. (org-columns-compile-format) (org-columns-get-autowidth-alist, org-buffer-property-keys) (org-entry-properties, org-at-property-p): Allow [:alnum:] in property names. (org-export-visible): Fix drawers before export. (org-do-sort): Allow sorting by priority. (org-agenda-files): Ignore non-existing files. (org-ellipsis): All a face as value. (org-mode): Interprete the face value of `org-ellipsis'. (org-archive-subtree): Store context info in archived entry. (org-fast-tag-selection): Allow setting TODO states through this interface. (org-cycle): Docstring updated. (org-set-font-lock-defaults, org-agenda-highlight-todo): Use `org-get-todo-face'. (org-table-edit-field, org-table-show-reference) (org-table-edit-formulas, org-add-log-note) (org-fast-tag-selection, org-agenda, org-prepare-agenda) (org-timeline): Use `org-switch-to-buffer-other-window' instead of `switch-to-buffer-other-window' to make sure that the temporary windows show up on the current frame. (org-mhe-get-message-real-folder, org-batch-store-agenda-views) (org-get-entries-from-diary, org-replace-region-by-html): Don't allow pop-up frames. (org-agenda-get-deadlines, org-agenda-get-scheduled): Fix problems with time-of-day. (org-agenda-get-scheduled, org-agenda-get-deadlines): Fix problems with listing items that are DONE. (org-change-tag-in-region): New command. (org-agenda-skip-scheduled-if-done) (org-agenda-skip-deadline-if-done): Docstring clarified. (org-mode): Hide drawers on startup. (org-set-regexps-and-options): Use `org-remove-keyword-keys'. (org-agenda-skip): Allow a form for `org-agenda-skip-function'. (org-agenda-redo): Re-use local settings. (org-agenda): Store local settings. (org-agenda-get-deadlines, org-agenda-get-scheduled): Also handle entries on their due date. (org-agenda-get-timestamps): No longer handle the due dates of schedules and deadline items. (org-insert-link-global, org-open-at-point-global): New commands. (org-export-as-ascii): Call `org-cleaned-string-for-export' with a :for-ascii parameter. (org-skip-comments): Function removed. (org-cleaned-string-for-export): Handle special table lines. (org-entry-get-with-inheritance): Check global properties. (org-set-regexps-and-options): Find the #+PROPERTY line. (org-link-types): Change type into variable (was constant). (org-link-re-with-space, org-link-re-with-space2) (org-angle-link-re, org-plain-link-re, org-bracket-link-regexp) (org-bracket-link-analytic-regexp, org-any-link-re): Creation of these regular expressions happens now in the function `org-make-link-regexps'. (org-store-link): Call the functions in `org-store-link-functions'. (org-activate-tags): Force matches to be in headlines. (org-batch-store-agenda-views): Fix bug with killing agenda buffer. (org-columns-display-here): Make sure this works in a narrowed buffer by checking for point-min. (org-columns-display-here): Make the rest of the line intangible, so that point never can be there. (org-cleaned-string-for-export): Use `with-current-buffer'. (org-replace-region-by-html): Use `with-current-buffer'. (org-unfontify-region, org-do-occur, org-columns-display-here) (org-columns-remove-overlays, org-columns-quit) (org-columns-edit-value, org-columns-next-allowed-value) (org-eval-in-calendar, org-agenda-undo, org-no-read-only) (org-finalize-agenda, org-remove-subtree-entries-from-agenda) (org-agenda-todo, org-agenda-change-all-lines) (org-agenda-align-tags, org-agenda-priority) (org-agenda-set-tags, org-agenda-toggle-archive-tag) (org-agenda-show-new-time, org-cleaned-string-for-export) (org-export-grab-title-from-buffer) (org-export-as-ascii, org-export-as-html): Use `inhibit-read-only' instead of `buffer-read-only'. (org-export-as-html): Set `coding-system-for-write'. (org-archive-subtree): Fixed bug with modifying TODO keyword. (org-beginning-of-line): Also treat C-a special in items. (org-table-convert-refs-to-rc): Fixed problem with column reference after "..". (org-columns-compute): Don't mark buffer modified because of text properties. (org-batch-store-agenda-views): Use the variable `default-directory', not the function. (org-clock-out-if-current): Respect `org-clock-out-when-done'. (org-html-entities): Added HTML entities for smileys. (org-end-of-line): Move to end of line if in headline without tags. (org-agenda-day-view, org-agenda-week-view): Remember span as default. (org-columns-edit-value): Rename from `org-column-edit'. (org-columns-display-here-title): Rename from `org-overlay-columns-title'. (org-columns-remove-overlays): Rename from org-remove-column-overlays. (org-columns-get-autowidth-alist): Rename from `org-get-columns-autowidth-alist'. (org-columns-display-here): Rename from `org-overlay-columns'. (org-columns-new-overlay): Rename from `org-new-column-overlay'. (org-columns-quit): Rename from `org-column-quit'. (org-columns-show-value): Rename from `org-column-show-value'. (org-columns-current-fmt): Rename from `org-current-columns-fmt'. (org-columns-overlays): Rename from `org-column-overlays'. (org-columns-map): Rename from `org-column-map'. (org-columns-current-maxwidths): Rename from `org-current-columns-maxwidths'. (org-columns-begin-marker, org-columns-current-fmt-compiled) (org-previous-header-line-format) (org-columns-inhibit-recalculation) (org-columns-default-format): Rename from `org-default-columns-format'. (org-property-re): New constant. (orgstruct-mode): New minor mode. (org-cycle-list-bullet): New command. (org-special-properties, org-property-start-re) (org-property-end-re): New constants. (org-with-point-at): New macro. (org-insert-property-drawer): New command. (org-column): New face. (org-column-menu): New menu. (org-columns, org-agenda-columns): New commands. (org-properties): New customize group. (org-priority): Realign tags after changing priority. (org-preserve-lc): New macro. (org-update-checkbox-count): Catch case when there is no headline. (org-agenda-quit): Remove any column overlays. (org-beginning-of-item-list): Fixed bug when non-item line is indented too deep. (org-make-tags-matcher): Handle property matches. (org-table-recalculate): Swap evaluation order: Field formula first, then column formulas, but don't allow them to overwrite the field formulas. (org-table-eval-formula): New argument untouchable. (org-export-as-html): Fix replacement bug for XEmacs. --- lisp/textmodes/org-export-latex.el | 1539 +++ lisp/textmodes/org-irc.el | 228 + lisp/textmodes/org-mac-message.el | 78 + lisp/textmodes/org-mouse.el | 1110 ++ lisp/textmodes/org-publish.el | 655 ++ lisp/textmodes/org.el | 16171 +++++++++++++++++++++------ man/ChangeLog | 5 + 7 files changed, 16219 insertions(+), 3567 deletions(-) create mode 100644 lisp/textmodes/org-export-latex.el create mode 100644 lisp/textmodes/org-irc.el create mode 100644 lisp/textmodes/org-mac-message.el create mode 100644 lisp/textmodes/org-mouse.el create mode 100644 lisp/textmodes/org-publish.el diff --git a/lisp/textmodes/org-export-latex.el b/lisp/textmodes/org-export-latex.el new file mode 100644 index 00000000000..d8dbeed4f76 --- /dev/null +++ b/lisp/textmodes/org-export-latex.el @@ -0,0 +1,1539 @@ +;;; org-export-latex.el --- LaTeX exporter for org-mode +;; +;; Copyright (c) 2007, 2008 Free Software Foundation, Inc. +;; +;; Emacs Lisp Archive Entry +;; Filename: org-export-latex.el +;; Version: 5.23 +;; Author: Bastien Guerry +;; Maintainer: Bastien Guerry +;; Keywords: org, wp, tex +;; Description: Converts an org-mode buffer into LaTeX +;; URL: http://www.cognition.ens.fr/~guerry/u/org-export-latex.el +;; +;; This file is part of GNU Emacs. +;; +;; GNU Emacs is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by the +;; Free Software Foundation; either version 3, or (at your option) any +;; later version. +;; +;; GNU Emacs is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301, USA. +;; +;;; Commentary: +;; +;; This library implements a LaTeX exporter for org-mode. +;; +;; Put this file into your load-path and the following into your ~/.emacs: +;; (require 'org-export-latex) +;; +;; The interactive functions are similar to those of the HTML exporter: +;; +;; M-x `org-export-as-latex' +;; M-x `org-export-as-latex-batch' +;; M-x `org-export-as-latex-to-buffer' +;; M-x `org-export-region-as-latex' +;; M-x `org-replace-region-by-latex' +;; +;;; Code: + +(eval-when-compile + (require 'cl)) + +(require 'footnote) +(require 'org) + +;;; Variables: +(defvar org-export-latex-class nil) +(defvar org-export-latex-header nil) +(defvar org-export-latex-append-header nil) +(defvar org-export-latex-options-plist nil) +(defvar org-export-latex-todo-keywords-1 nil) +(defvar org-export-latex-all-targets-re nil) +(defvar org-export-latex-add-level 0) +(defvar org-export-latex-sectioning "") +(defvar org-export-latex-sectioning-depth 0) +(defvar org-export-latex-list-beginning-re + "^\\([ \t]*\\)\\([-+*]\\|[0-9]+[.)]\\) +?") + +(defvar org-export-latex-special-string-regexps + '(org-ts-regexp + org-scheduled-string + org-deadline-string + org-clock-string) + "A list of regexps to convert as special keywords.") + +(defvar latexp) ; dynamically scoped from org.el +(defvar re-quote) ; dynamically scoped from org.el +(defvar commentsp) ; dynamically scoped from org.el + +;;; User variables: + +(defcustom org-export-latex-default-class "article" + "The default LaTeX class." + :group 'org-export-latex + :type '(string :tag "LaTeX class")) + +(defcustom org-export-latex-classes + '(("article" + "\\documentclass[11pt,a4paper]{article} +\\usepackage[utf8]{inputenc} +\\usepackage[T1]{fontenc} +\\usepackage{hyperref}" + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}") + ("\\paragraph{%s}" . "\\paragraph*{%s}") + ("\\subparagraph{%s}" . "\\subparagraph*{%s}")) + ("report" + "\\documentclass[11pt,a4paper]{report} +\\usepackage[utf8]{inputenc} +\\usepackage[T1]{fontenc} +\\usepackage{hyperref}" + ("\\part{%s}" . "\\part*{%s}") + ("\\chapter{%s}" . "\\chapter*{%s}") + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}")) + ("book" + "\\documentclass[11pt,a4paper]{book} +\\usepackage[utf8]{inputenc} +\\usepackage[T1]{fontenc} +\\usepackage{hyperref}" + ("\\part{%s}" . "\\part*{%s}") + ("\\chapter{%s}" . "\\chapter*{%s}") + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))) + "Alist of LaTeX classes and associated header and structure. +If #+LaTeX_CLASS is set in the buffer, use its value and the +associated information. Here is the structure of each cell: + + \(class-name + header-string + (unnumbered-section numbered-section\) + ...\) + +A %s formatter is mandatory in each section string and will be +replaced by the title of the section." + :group 'org-export-latex + :type '(repeat + (list (string :tag "LaTeX class") + (string :tag "LaTeX header") + (cons :tag "Level 1" + (string :tag "Numbered") + (string :tag "Unnumbered")) + (cons :tag "Level 2" + (string :tag "Numbered") + (string :tag "Unnumbered")) + (cons :tag "Level 3" + (string :tag "Numbered") + (string :tag "Unnumbered")) + (cons :tag "Level 4" + (string :tag "Numbered") + (string :tag "Unnumbered")) + (cons :tag "Level 5" + (string :tag "Numbered") + (string :tag "Unnumbered"))))) + +(defcustom org-export-latex-emphasis-alist + '(("*" "\\textbf{%s}" nil) + ("/" "\\emph{%s}" nil) + ("_" "\\underline{%s}" nil) + ("+" "\\texttt{%s}" nil) + ("=" "\\texttt{%s}" nil) + ("~" "\\texttt{%s}" t)) + "Alist of LaTeX expressions to convert emphasis fontifiers. +Each element of the list is a list of three elements. +The first element is the character used as a marker for fontification. +The second element is a formatting string to wrap fontified text with. +The third element decides whether to protect converted text from other +conversions." + :group 'org-export-latex + :type 'alist) + +(defcustom org-export-latex-title-command "\\maketitle" + "The command used to insert the title just after \\begin{document}. +If this string contains the formatting specification \"%s\" then +it will be used as a formatting string, passing the title as an +argument." + :group 'org-export-latex + :type 'string) + +(defcustom org-export-latex-date-format + "%d %B %Y" + "Format string for \\date{...}." + :group 'org-export-latex + :type 'string) + +(defcustom org-export-latex-tables-verbatim nil + "When non-nil, export tables as verbatim." + :group 'org-export-latex + :type 'boolean) + +(defcustom org-export-latex-tables-column-borders nil + "When non-nil, group of columns are surrounded with borders, +XSeven if these borders are the outside borders of the table." + :group 'org-export-latex + :type 'boolean) + +(defcustom org-export-latex-packages-alist nil + "Alist of packages to be inserted in the header. +Each cell is of the forma \( \"option\" . \"package\" \)." + :group 'org-export-latex + :type 'alist) + +(defcustom org-export-latex-low-levels 'description + "How to convert sections below the current level of sectioning, +as specified by `org-export-headline-levels' or the value of \"H:\" +in Org's #+OPTION line. + +This can be either nil (skip the sections), 'description (convert +the sections as descriptive lists) or a string to be used instead +of \\section{%s}. In this latter case, the %s stands here for the +inserted headline and is mandatory." + :group 'org-export-latex + :type '(choice (const :tag "Ignore" nil) + (symbol :tag "Convert as descriptive list" description) + (string :tag "Use a section string" :value "\\subparagraph{%s}"))) + +(defcustom org-export-latex-remove-from-headlines + '(:todo t :priority t :tags t) + "A plist of keywords to remove from headlines. +Non-nil means remove this keyword type from the headline. + +Don't remove the keys, just change their values." + :type 'plist + :group 'org-export-latex) + +(defcustom org-export-latex-image-default-option "width=10em" + "Default option for images." + :group 'org-export-latex + :type 'string) + +(defcustom org-export-latex-coding-system nil + "Coding system for the exported LaTex file." + :group 'org-export-latex + :type 'coding-system) + +(defcustom org-list-radio-list-templates + '((latex-mode "% BEGIN RECEIVE ORGLST %n +% END RECEIVE ORGLST %n +\\begin{comment} +#+ORGLST: SEND %n org-list-to-latex +| | | +\\end{comment}\n") + (texinfo-mode "@c BEGIN RECEIVE ORGLST %n +@c END RECEIVE ORGLST %n +@ignore +#+ORGLST: SEND %n org-list-to-texinfo +| | | +@end ignore\n") + (html-mode " + +\n")) + "Templates for radio lists in different major modes. +All occurrences of %n in a template will be replaced with the name of the +list, obtained by prompting the user." + :group 'org-plain-lists + :type '(repeat + (list (symbol :tag "Major mode") + (string :tag "Format")))) + +;;; Autoload functions: + +;;;###autoload +(defun org-export-as-latex-batch () + "Call `org-export-as-latex', may be used in batch processing as +emacs --batch + --load=$HOME/lib/emacs/org.el + --eval \"(setq org-export-headline-levels 2)\" + --visit=MyFile --funcall org-export-as-latex-batch" + (org-export-as-latex org-export-headline-levels 'hidden)) + +;;;###autoload +(defun org-export-as-latex-to-buffer (arg) + "Call `org-exort-as-latex` with output to a temporary buffer. +No file is created. The prefix ARG is passed through to `org-export-as-latex'." + (interactive "P") + (org-export-as-latex arg nil nil "*Org LaTeX Export*") + (switch-to-buffer-other-window "*Org LaTeX Export*")) + +;;;###autoload +(defun org-replace-region-by-latex (beg end) + "Replace the region from BEG to END with its LaTeX export. +It assumes the region has `org-mode' syntax, and then convert it to +LaTeX. This can be used in any buffer. For example, you could +write an itemized list in `org-mode' syntax in an LaTeX buffer and +then use this command to convert it." + (interactive "r") + (let (reg latex buf) + (save-window-excursion + (if (org-mode-p) + (setq latex (org-export-region-as-latex + beg end t 'string)) + (setq reg (buffer-substring beg end) + buf (get-buffer-create "*Org tmp*")) + (save-excursion + (set-buffer buf) + (erase-buffer) + (insert reg) + (org-mode) + (setq latex (org-export-region-as-latex + (point-min) (point-max) t 'string))) + (kill-buffer buf))) + (delete-region beg end) + (insert latex))) + +;;;###autoload +(defun org-export-region-as-latex (beg end &optional body-only buffer) + "Convert region from BEG to END in `org-mode' buffer to LaTeX. +If prefix arg BODY-ONLY is set, omit file header, footer, and table of +contents, and only produce the region of converted text, useful for +cut-and-paste operations. +If BUFFER is a buffer or a string, use/create that buffer as a target +of the converted LaTeX. If BUFFER is the symbol `string', return the +produced LaTeX as a string and leave not buffer behind. For example, +a Lisp program could call this function in the following way: + + (setq latex (org-export-region-as-latex beg end t 'string)) + +When called interactively, the output buffer is selected, and shown +in a window. A non-interactive call will only retunr the buffer." + (interactive "r\nP") + (when (interactive-p) + (setq buffer "*Org LaTeX Export*")) + (let ((transient-mark-mode t) (zmacs-regions t) + rtn) + (goto-char end) + (set-mark (point)) ;; to activate the region + (goto-char beg) + (setq rtn (org-export-as-latex + nil nil nil + buffer body-only)) + (if (fboundp 'deactivate-mark) (deactivate-mark)) + (if (and (interactive-p) (bufferp rtn)) + (switch-to-buffer-other-window rtn) + rtn))) + +;;;###autoload +(defun org-export-as-latex (arg &optional hidden ext-plist + to-buffer body-only pub-dir) + "Export current buffer to a LaTeX file. +If there is an active region, export only the region. The prefix +ARG specifies how many levels of the outline should become +headlines. The default is 3. Lower levels will be exported +depending on `org-export-latex-low-levels'. The default is to +convert them as description lists. When HIDDEN is non-nil, don't +display the LaTeX buffer. EXT-PLIST is a property list with +external parameters overriding org-mode's default settings, but +still inferior to file-local settings. When TO-BUFFER is +non-nil, create a buffer with that name and export to that +buffer. If TO-BUFFER is the symbol `string', don't leave any +buffer behind but just return the resulting LaTeX as a string. +When BODY-ONLY is set, don't produce the file header and footer, +simply return the content of \begin{document}...\end{document}, +without even the \begin{document} and \end{document} commands. +when PUB-DIR is set, use this as the publishing directory." + (interactive "P") + ;; Make sure we have a file name when we need it. + (when (and (not (or to-buffer body-only)) + (not buffer-file-name)) + (if (buffer-base-buffer) + (org-set-local 'buffer-file-name + (with-current-buffer (buffer-base-buffer) + buffer-file-name)) + (error "Need a file name to be able to export"))) + + (message "Exporting to LaTeX...") + (org-update-radio-target-regexp) + (org-export-latex-set-initial-vars ext-plist arg) + (let* ((wcf (current-window-configuration)) + (opt-plist org-export-latex-options-plist) + (region-p (org-region-active-p)) + (subtree-p + (when region-p + (save-excursion + (goto-char (region-beginning)) + (and (org-at-heading-p) + (>= (org-end-of-subtree t t) (region-end)))))) + (title (or (and subtree-p (org-export-get-title-from-subtree)) + (plist-get opt-plist :title) + (and (not + (plist-get opt-plist :skip-before-1st-heading)) + (org-export-grab-title-from-buffer)) + (file-name-sans-extension + (file-name-nondirectory buffer-file-name)))) + (filename (concat (file-name-as-directory + (or pub-dir + (org-export-directory :LaTeX ext-plist))) + (file-name-sans-extension + (file-name-nondirectory ;sans-extension + buffer-file-name)) ".tex")) + (filename (if (equal (file-truename filename) + (file-truename buffer-file-name)) + (concat filename ".tex") + filename)) + (buffer (if to-buffer + (cond + ((eq to-buffer 'string) (get-buffer-create + "*Org LaTeX Export*")) + (t (get-buffer-create to-buffer))) + (find-file-noselect filename))) + (odd org-odd-levels-only) + (header (org-export-latex-make-header title opt-plist)) + (skip (cond (subtree-p nil) + (region-p t) + ;; never skip first lines when exporting a subtree + (t (plist-get opt-plist :skip-before-1st-heading)))) + (text (plist-get opt-plist :text)) + (first-lines (if skip "" (org-export-latex-first-lines))) + (coding-system (and (boundp 'buffer-file-coding-system) + buffer-file-coding-system)) + (coding-system-for-write (or org-export-latex-coding-system + coding-system)) + (save-buffer-coding-system (or org-export-latex-coding-system + coding-system)) + (region (buffer-substring + (if region-p (region-beginning) (point-min)) + (if region-p (region-end) (point-max)))) + (string-for-export + (org-cleaned-string-for-export + region :emph-multiline t + :for-LaTeX t + :comments nil + :add-text (if (eq to-buffer 'string) nil text) + :skip-before-1st-heading skip + :LaTeX-fragments nil))) + + (set-buffer buffer) + (erase-buffer) + + (and (fboundp 'set-buffer-file-coding-system) + (set-buffer-file-coding-system coding-system-for-write)) + + ;; insert the header and initial document commands + (unless (or (eq to-buffer 'string) body-only) + (insert header)) + + ;; insert text found in #+TEXT + (when (and text (not (eq to-buffer 'string))) + (insert (org-export-latex-content + text '(lists tables fixed-width keywords)) + "\n\n")) + + ;; insert lines before the first headline + (unless (or skip (eq to-buffer 'string)) + (insert first-lines)) + + ;; handle the case where the region does not begin with a section + (when region-p + (insert (with-temp-buffer + (insert string-for-export) + (org-export-latex-first-lines)))) + + ;; export the content of headlines + (org-export-latex-global + (with-temp-buffer + (insert string-for-export) + (goto-char (point-min)) + (when (re-search-forward "^\\(\\*+\\) " nil t) + (let* ((asters (length (match-string 1))) + (level (if odd (- asters 2) (- asters 1)))) + (setq org-export-latex-add-level + (if odd (1- (/ (1+ asters) 2)) (1- asters))) + (org-export-latex-parse-global level odd))))) + + ;; finalization + (unless body-only (insert "\n\\end{document}")) + (or to-buffer (save-buffer)) + (goto-char (point-min)) + (message "Exporting to LaTeX...done") + (prog1 + (if (eq to-buffer 'string) + (prog1 (buffer-substring (point-min) (point-max)) + (kill-buffer (current-buffer))) + (current-buffer)) + (set-window-configuration wcf)))) + +;;; Parsing functions: + +(defun org-export-latex-parse-global (level odd) + "Parse the current buffer recursively, starting at LEVEL. +If ODD is non-nil, assume the buffer only contains odd sections. +Return a list reflecting the document structure." + (save-excursion + (goto-char (point-min)) + (let* ((cnt 0) output + (depth org-export-latex-sectioning-depth)) + (while (re-search-forward + (concat "^\\(\\(?:\\*\\)\\{" + (number-to-string (+ (if odd 2 1) level)) + "\\}\\) \\(.*\\)$") + ;; make sure that there is no upper heading + (when (> level 0) + (save-excursion + (save-match-data + (re-search-forward + (concat "^\\(\\(?:\\*\\)\\{" + (number-to-string level) + "\\}\\) \\(.*\\)$") nil t)))) t) + (setq cnt (1+ cnt)) + (let* ((pos (match-beginning 0)) + (heading (match-string 2)) + (nlevel (if odd (/ (+ 3 level) 2) (1+ level)))) + (save-excursion + (narrow-to-region + (point) + (save-match-data + (if (re-search-forward + (concat "^\\(\\(?:\\*\\)\\{" + (number-to-string (+ (if odd 2 1) level)) + "\\}\\) \\(.*\\)$") nil t) + (match-beginning 0) + (point-max)))) + (goto-char (point-min)) + (setq output + (append output + (list + (list + `(pos . ,pos) + `(level . ,nlevel) + `(occur . ,cnt) + `(heading . ,heading) + `(content . ,(org-export-latex-parse-content)) + `(subcontent . ,(org-export-latex-parse-subcontent + level odd))))))) + (widen))) + (list output)))) + +(defun org-export-latex-parse-content () + "Extract the content of a section." + (let ((beg (point)) + (end (if (re-search-forward "^\\(\\*\\)+ .*$" nil t) + (progn (beginning-of-line) (point)) + (point-max)))) + (buffer-substring beg end))) + +(defun org-export-latex-parse-subcontent (level odd) + "Extract the subcontent of a section at LEVEL. +If ODD Is non-nil, assume subcontent only contains odd sections." + (if (not (re-search-forward + (concat "^\\(\\(?:\\*\\)\\{" + (number-to-string (+ (if odd 4 2) level)) + "\\}\\) \\(.*\\)$") + nil t)) + nil ; subcontent is nil + (org-export-latex-parse-global (+ (if odd 2 1) level) odd))) + +;;; Rendering functions: +(defun org-export-latex-global (content) + "Export CONTENT to LaTeX. +CONTENT is an element of the list produced by +`org-export-latex-parse-global'." + (if (eq (car content) 'subcontent) + (mapc 'org-export-latex-sub (cdr content)) + (org-export-latex-sub (car content)))) + +(defun org-export-latex-sub (subcontent) + "Export the list SUBCONTENT to LaTeX. +SUBCONTENT is an alist containing information about the headline +and its content." + (let ((num (plist-get org-export-latex-options-plist :section-numbers))) + (mapc (lambda(x) (org-export-latex-subcontent x num)) subcontent))) + +(defun org-export-latex-subcontent (subcontent num) + "Export each cell of SUBCONTENT to LaTeX." + (let ((heading (org-export-latex-fontify-headline + (cdr (assoc 'heading subcontent)))) + (level (- (cdr (assoc 'level subcontent)) + org-export-latex-add-level)) + (occur (number-to-string (cdr (assoc 'occur subcontent)))) + (content (cdr (assoc 'content subcontent))) + (subcontent (cadr (assoc 'subcontent subcontent)))) + (cond + ;; Normal conversion + ((<= level org-export-latex-sectioning-depth) + (let ((sec (nth (1- level) org-export-latex-sectioning))) + (insert (format (if num (car sec) (cdr sec)) heading) "\n")) + (insert (org-export-latex-content content)) + (cond ((stringp subcontent) (insert subcontent)) + ((listp subcontent) (org-export-latex-sub subcontent)))) + ;; At a level under the hl option: we can drop this subsection + ((> level org-export-latex-sectioning-depth) + (cond ((eq org-export-latex-low-levels 'description) + (insert (format "\\begin{description}\n\n\\item[%s]\n\n" heading)) + (insert (org-export-latex-content content)) + (cond ((stringp subcontent) (insert subcontent)) + ((listp subcontent) (org-export-latex-sub subcontent))) + (insert "\\end{description}\n")) + ((stringp org-export-latex-low-levels) + (insert (format org-export-latex-low-levels heading) "\n") + (insert (org-export-latex-content content)) + (cond ((stringp subcontent) (insert subcontent)) + ((listp subcontent) (org-export-latex-sub subcontent))))))))) + +;;; Exporting internals: +(defun org-export-latex-set-initial-vars (ext-plist level) + "Store org local variables required for LaTeX export. +EXT-PLIST is an optional additional plist. +LEVEL indicates the default depth for export." + (setq org-export-latex-todo-keywords-1 org-todo-keywords-1 + org-export-latex-all-targets-re + (org-make-target-link-regexp (org-all-targets)) + org-export-latex-options-plist + (org-combine-plists (org-default-export-plist) ext-plist + (org-infile-export-plist)) + org-export-latex-class + (save-excursion + (goto-char (point-min)) + (if (and (re-search-forward "^#\\+LaTeX_CLASS:[ \t]*\\([a-zA-Z]+\\)" nil t) + (assoc (match-string 1) org-export-latex-classes)) + (match-string 1) + org-export-latex-default-class)) + org-export-latex-header + (cadr (assoc org-export-latex-class org-export-latex-classes)) + org-export-latex-sectioning + (cddr (assoc org-export-latex-class org-export-latex-classes)) + org-export-latex-sectioning-depth + (or level + (let ((hl-levels + (plist-get org-export-latex-options-plist :headline-levels)) + (sec-depth (length org-export-latex-sectioning))) + (if (> hl-levels sec-depth) sec-depth hl-levels))))) + +(defun org-export-latex-make-header (title opt-plist) + "Make the LaTeX header and return it as a string. +TITLE is the current title from the buffer or region. +OPT-PLIST is the options plist for current buffer." + (let ((toc (plist-get opt-plist :table-of-contents)) + (author (plist-get opt-plist :author))) + (concat + (if (plist-get opt-plist :time-stamp-file) + (format-time-string "% Created %Y-%m-%d %a %H:%M\n")) + ;; insert LaTeX custom header + org-export-latex-header + "\n" + ;; insert information on LaTeX packages + (when org-export-latex-packages-alist + (mapconcat (lambda(p) + (if (equal "" (car p)) + (format "\\usepackage{%s}" (cadr p)) + (format "\\usepackage[%s]{%s}" + (car p) (cadr p)))) + org-export-latex-packages-alist "\n")) + ;; insert additional commands in the header + org-export-latex-append-header + ;; insert the title + (format + "\n\n\\title{%s}\n" + ;; convert the title + (org-export-latex-content + title '(lists tables fixed-width keywords))) + ;; insert author info + (if (plist-get opt-plist :author-info) + (format "\\author{%s}\n" + (or author user-full-name)) + (format "%%\\author{%s}\n" + (or author user-full-name))) + ;; insert the date + (format "\\date{%s}\n" + (format-time-string + (or (plist-get opt-plist :date) + org-export-latex-date-format))) + ;; beginning of the document + "\n\\begin{document}\n\n" + ;; insert the title command + (if (string-match "%s" org-export-latex-title-command) + (format org-export-latex-title-command title) + org-export-latex-title-command) + "\n\n" + ;; table of contents + (when (and org-export-with-toc + (plist-get opt-plist :section-numbers)) + (cond ((numberp toc) + (format "\\setcounter{tocdepth}{%s}\n\\tableofcontents\n\n" + (min toc (plist-get opt-plist :headline-levels)))) + (toc (format "\\setcounter{tocdepth}{%s}\n\\tableofcontents\n\n" + (plist-get opt-plist :headline-levels)))))))) + +(defun org-export-latex-first-lines (&optional comments) + "Export the first lines before first headline. +COMMENTS is either nil to replace them with the empty string or a +formatting string like %%%%s if we want to comment them out." + (save-excursion + (goto-char (point-min)) + (if (org-at-heading-p) (beginning-of-line 2)) + (let* ((pt (point)) + (end (if (and (re-search-forward "^\\* " nil t) + (not (eq pt (match-beginning 0)))) + (goto-char (match-beginning 0)) + (goto-char (point-max))))) + (org-export-latex-content + (org-cleaned-string-for-export + (buffer-substring (point-min) end) + :for-LaTeX t + :emph-multiline t + :add-text nil + :comments nil + :skip-before-1st-heading nil + :LaTeX-fragments nil))))) + +(defun org-export-latex-content (content &optional exclude-list) + "Convert CONTENT string to LaTeX. +Don't perform conversions that are in EXCLUDE-LIST. Recognized +conversion types are: quotation-marks, emphasis, sub-superscript, +links, keywords, lists, tables, fixed-width" + (with-temp-buffer + (insert content) + (unless (memq 'quotation-marks exclude-list) + (org-export-latex-quotation-marks)) + (unless (memq 'emphasis exclude-list) + (when (plist-get org-export-latex-options-plist :emphasize) + (org-export-latex-fontify))) + (unless (memq 'sub-superscript exclude-list) + (org-export-latex-special-chars + (plist-get org-export-latex-options-plist :sub-superscript))) + (unless (memq 'links exclude-list) + (org-export-latex-links)) + (unless (memq 'keywords exclude-list) + (org-export-latex-keywords + (plist-get org-export-latex-options-plist :timestamps))) + (unless (memq 'lists exclude-list) + (org-export-latex-lists)) + (unless (memq 'tables exclude-list) + (org-export-latex-tables + (plist-get org-export-latex-options-plist :tables))) + (unless (memq 'fixed-width exclude-list) + (org-export-latex-fixed-width + (plist-get org-export-latex-options-plist :fixed-width))) + ;; return string + (buffer-substring (point-min) (point-max)))) + +(defun org-export-latex-protect-string (s) + "Prevent further conversion for string S by adding the +org-protect property." + (add-text-properties 0 (length s) '(org-protected t) s) s) + +(defun org-export-latex-protect-char-in-string (char-list string) + "Add org-protected text-property to char from CHAR-LIST in STRING." + (with-temp-buffer + (save-match-data + (insert string) + (goto-char (point-min)) + (while (re-search-forward (regexp-opt char-list) nil t) + (add-text-properties (match-beginning 0) + (match-end 0) '(org-protected t))) + (buffer-string)))) + +(defun org-export-latex-keywords-maybe (remove-list) + "Maybe remove keywords depending on rules in REMOVE-LIST." + (goto-char (point-min)) + (let ((re-todo (mapconcat 'identity org-export-latex-todo-keywords-1 "\\|")) + (case-fold-search nil)) + ;; convert TODO keywords + (when (re-search-forward (concat "^\\(" re-todo "\\)") nil t) + (if (plist-get remove-list :todo) + (replace-match "") + (replace-match (format "\\texttt{%s}" (match-string 1)) t t))) + ;; convert priority string + (when (re-search-forward "\\[\\\\#.\\]" nil t) + (if (plist-get remove-list :priority) + (replace-match "") + (replace-match (format "\\texttt{%s}" (match-string 0)) t t))) + ;; convert tags + (when (re-search-forward "\\(:[a-zA-Z0-9]+\\)+:" nil t) + (if (or (not org-export-with-tags) + (plist-get remove-list :tags)) + (replace-match "") + (replace-match (format "\\texttt{%s}" (match-string 0)) t t))))) + +(defun org-export-latex-fontify-headline (string) + "Fontify special words in string." + (with-temp-buffer + ;; FIXME: org-inside-LaTeX-fragment-p doesn't work when the $...$ is at + ;; the beginning of the buffer - inserting "\n" is safe here though. + (insert "\n" string) + (goto-char (point-min)) + (when (plist-get org-export-latex-options-plist :emphasize) + (org-export-latex-fontify)) + (org-export-latex-special-chars + (plist-get org-export-latex-options-plist :sub-superscript)) + (org-export-latex-keywords-maybe + org-export-latex-remove-from-headlines) + (org-export-latex-links) + (org-trim (buffer-substring-no-properties (point-min) (point-max))))) + +(defun org-export-latex-quotation-marks () + "Export question marks depending on language conventions." + (let* ((lang (plist-get org-export-latex-options-plist :language)) + (quote-rpl (if (equal lang "fr") + '(("\\(\\s-\\)\"" "«~") + ("\\(\\S-\\)\"" "~»") + ("\\(\\s-\\)'" "`")) + '(("\\(\\s-\\)\"" "``") + ("\\(\\S-\\)\"" "''") + ("\\(\\s-\\)'" "`"))))) + (mapc (lambda(l) (goto-char (point-min)) + (while (re-search-forward (car l) nil t) + (let ((rpl (concat (match-string 1) (cadr l)))) + (org-export-latex-protect-string rpl) + (org-if-unprotected + (replace-match rpl t t))))) quote-rpl))) + +(defun org-export-latex-special-chars (sub-superscript) + "Export special characters to LaTeX. +If SUB-SUPERSCRIPT is non-nil, convert \\ and ^. +See the `org-export-latex.el' code for a complete conversion table." + (goto-char (point-min)) + (mapc (lambda(c) + (goto-char (point-min)) + (while (re-search-forward c nil t) + ;; Put the point where to check for org-protected + (unless (or (get-text-property (match-beginning 2) 'org-protected) + (org-at-table-p)) + (cond ((member (match-string 2) '("\\$" "$")) + (if (equal (match-string 2) "\\$") + (replace-match (concat (match-string 1) "$" + (match-string 3)) t t) + (replace-match (concat (match-string 1) "\\$" + (match-string 3)) t t))) + ((member (match-string 2) '("&" "%" "#")) + (if (equal (match-string 1) "\\") + (replace-match (match-string 2) t t) + (replace-match (concat (match-string 1) "\\" + (match-string 2)) t t))) + ((equal (match-string 2) "...") + (replace-match + (concat (match-string 1) + (org-export-latex-protect-string "\\ldots{}")) t t)) + ((equal (match-string 2) "~") + (cond ((equal (match-string 1) "\\") nil) + ((eq 'org-link (get-text-property 0 'face (match-string 2))) + (replace-match (concat (match-string 1) "\\~") t t)) + (t (replace-match + (org-export-latex-protect-string + (concat (match-string 1) "\\~{}")) t t)))) + ((member (match-string 2) '("{" "}")) + (unless (save-match-data (org-inside-LaTeX-fragment-p)) + (if (equal (match-string 1) "\\") + (replace-match (match-string 2) t t) + (replace-match (concat (match-string 1) "\\" + (match-string 2)) t t))))) + (unless (save-match-data (org-inside-LaTeX-fragment-p)) + (cond ((equal (match-string 2) "\\") + (replace-match (or (save-match-data + (org-export-latex-treat-backslash-char + (match-string 1) + (match-string 3))) "") t t)) + ((member (match-string 2) '("_" "^")) + (replace-match (or (save-match-data + (org-export-latex-treat-sub-super-char + sub-superscript + (match-string 1) + (match-string 2) + (match-string 3))) "") t t))))))) + '("^\\([^\n$]*?\\|^\\)\\(\\\\?\\$\\)\\([^\n$]*\\)$" + "\\([a-za-z0-9]+\\|[ \t\n]\\|\\b\\|\\\\\\)\\(_\\|\\^\\)\\([a-za-z0-9]+\\|[ \t\n]\\|[:punct:]\\|{[a-za-z0-9]+}\\|([a-za-z0-9]+)\\)" + "\\(.\\|^\\)\\(\\\\\\)\\([ \t\n]\\|[a-zA-Z&#%{}\"]+\\)" + "\\(.\\|^\\)\\(&\\)" + "\\(.\\|^\\)\\(#\\)" + "\\(.\\|^\\)\\(%\\)" + "\\(.\\|^\\)\\({\\)" + "\\(.\\|^\\)\\(}\\)" + "\\(.\\|^\\)\\(~\\)" + "\\(.\\|^\\)\\(\\.\\.\\.\\)" + ;; (?\< . "\\textless{}") + ;; (?\> . "\\textgreater{}") + ))) + +(defun org-export-latex-treat-sub-super-char + (subsup string-before char string-after) + "Convert the \"_\" and \"^\" characters to LaTeX. +SUBSUP corresponds to the ^: option in the #+OPTIONS line. +Convert CHAR depending on STRING-BEFORE and STRING-AFTER." + (cond ((equal string-before "\\") + (concat string-before char string-after)) + ;; this is part of a math formula + ((and (string-match "\\S-+" string-before) + (string-match "\\S-+" string-after)) + (cond ((eq 'org-link (get-text-property 0 'face char)) + (concat string-before "\\" char string-after)) + ((save-match-data (org-inside-LaTeX-fragment-p)) + (if subsup + (cond ((eq 1 (length string-after)) + (concat string-before char string-after)) + ((string-match "[({]?\\([^)}]+\\)[)}]?" string-after) + (format "%s%s{%s}" string-before char + (match-string 1 string-after)))))) + ((and subsup + (> (length string-after) 1) + (string-match "[({]?\\([^)}]+\\)[)}]?" string-after)) + (format "$%s%s{%s}$" string-before char + (match-string 1 string-after))) + (subsup (concat "$" string-before char string-after "$")) + (t (org-export-latex-protect-string + (concat string-before "\\" char "{}" string-after))))) + (t (org-export-latex-protect-string + (concat string-before "\\" char "{}" string-after))))) + +(defun org-export-latex-treat-backslash-char (string-before string-after) + "Convert the \"$\" special character to LaTeX. +The conversion is made depending of STRING-BEFORE and STRING-AFTER." + (cond ((member (list string-after) org-html-entities) + ;; backslash is part of a special entity (like "\alpha") + (concat string-before "$\\" + (or (cdar (member (list string-after) org-html-entities)) + string-after) "$")) + ((and (not (string-match "^[ \n\t]" string-after)) + (not (string-match "[ \t]\\'\\|^" string-before))) + ;; backslash is inside a word + (org-export-latex-protect-string + (concat string-before "\\textbackslash{}" string-after))) + ((not (or (equal string-after "") + (string-match "^[ \t\n]" string-after))) + ;; backslash might escape a character (like \#) or a user TeX + ;; macro (like \setcounter) + (org-export-latex-protect-string + (concat string-before "\\" string-after))) + ((and (string-match "^[ \t\n]" string-after) + (string-match "[ \t\n]\\'" string-before)) + ;; backslash is alone, convert it to $\backslash$ + (org-export-latex-protect-string + (concat string-before "\\textbackslash{}" string-after))) + (t (org-export-latex-protect-string + (concat string-before "\\textbackslash{}" string-after))))) + +(defun org-export-latex-keywords (timestamps) + "Convert special keywords to LaTeX. +Regexps are those from `org-export-latex-special-string-regexps'." + (let ((rg org-export-latex-special-string-regexps) r) + (while (setq r (pop rg)) + (goto-char (point-min)) + (while (re-search-forward (eval r) nil t) + (if (not timestamps) + (replace-match (format "\\\\texttt{%s}" (match-string 0)) t) + (replace-match "")))))) + +(defun org-export-latex-fixed-width (opt) + "When OPT is non-nil convert fixed-width sections to LaTeX." + (goto-char (point-min)) + (while (re-search-forward "^[ \t]*:" nil t) + (if opt + (progn (goto-char (match-beginning 0)) + (insert "\\begin{verbatim}\n") + (while (looking-at "^\\([ \t]*\\):\\(.*\\)$") + (replace-match (concat (match-string 1) + (match-string 2)) t t) + (forward-line)) + (insert "\\end{verbatim}\n\n")) + (progn (goto-char (match-beginning 0)) + (while (looking-at "^\\([ \t]*\\):\\(.*\\)$") + (replace-match (concat "%" (match-string 1) + (match-string 2)) t t) + (forward-line)))))) + +(defun org-export-latex-tables (insert) + "Convert tables to LaTeX and INSERT it." + (goto-char (point-min)) + (while (re-search-forward "^\\([ \t]*\\)|" nil t) + ;; FIXME really need to save-excursion? + (save-excursion (org-table-align)) + (let* ((beg (org-table-begin)) + (end (org-table-end)) + (raw-table (buffer-substring-no-properties beg end)) + fnum fields line lines olines gr colgropen line-fmt align) + (if org-export-latex-tables-verbatim + (let* ((tbl (concat "\\begin{verbatim}\n" raw-table + "\\end{verbatim}\n"))) + (apply 'delete-region (list beg end)) + (insert tbl)) + (progn + (setq lines (split-string raw-table "\n" t)) + (apply 'delete-region (list beg end)) + (when org-export-table-remove-special-lines + (setq lines (org-table-clean-before-export lines))) + ;; make a formatting string to reflect aligment + (setq olines lines) + (while (and (not line-fmt) (setq line (pop olines))) + (unless (string-match "^[ \t]*|-" line) + (setq fields (org-split-string line "[ \t]*|[ \t]*")) + (setq fnum (make-vector (length fields) 0)) + (setq line-fmt + (mapconcat + (lambda (x) + (setq gr (pop org-table-colgroup-info)) + (format "%s%%s%s" + (cond ((eq gr ':start) + (prog1 (if colgropen "|" "") + (setq colgropen t))) + ((eq gr ':startend) + (prog1 (if colgropen "|" "|") + (setq colgropen nil))) + (t "")) + (if (memq gr '(:end :startend)) + (progn (setq colgropen nil) "|") + ""))) + fnum "")))) + ;; fix double || in line-fmt + (setq line-fmt (replace-regexp-in-string "||" "|" line-fmt)) + ;; maybe remove the first and last "|" + (when (and (not org-export-latex-tables-column-borders) + (string-match "^\\(|\\)?\\(.+\\)|$" line-fmt)) + (setq line-fmt (match-string 2 line-fmt))) + ;; format alignment + (setq align (apply 'format + (cons line-fmt + (mapcar (lambda (x) (if x "r" "l")) + org-table-last-alignment)))) + ;; prepare the table to send to orgtbl-to-latex + (setq lines + (mapcar + (lambda(elem) + (or (and (string-match "[ \t]*|-+" elem) 'hline) + (split-string (org-trim elem) "|" t))) + lines)) + (when insert + (insert (orgtbl-to-latex + lines `(:tstart ,(concat "\\begin{tabular}{" align "}"))) + "\n\n"))))))) + +(defun org-export-latex-fontify () + "Convert fontification to LaTeX." + (goto-char (point-min)) + (while (re-search-forward org-emph-re nil t) + ;; The match goes one char after the *string* + (let ((emph (assoc (match-string 3) + org-export-latex-emphasis-alist)) + rpl) + (unless (get-text-property (1- (point)) 'org-protected) + (setq rpl (concat (match-string 1) + (format (org-export-latex-protect-char-in-string + '("\\" "{" "}") (cadr emph)) + (match-string 4)) + (match-string 5))) + (if (caddr emph) + (setq rpl (org-export-latex-protect-string rpl))) + (replace-match rpl t t))) + (backward-char))) + +(defun org-export-latex-links () + ;; Make sure to use the LaTeX hyperref and graphicx package + ;; or send some warnings. + "Convert links to LaTeX." + (goto-char (point-min)) + (while (re-search-forward org-bracket-link-analytic-regexp nil t) + (org-if-unprotected + (goto-char (match-beginning 0)) + (let* ((re-radio org-export-latex-all-targets-re) + (remove (list (match-beginning 0) (match-end 0))) + (type (match-string 2)) + (raw-path (match-string 3)) + (full-raw-path (concat (match-string 1) raw-path)) + (desc (match-string 5)) + imgp radiop + ;; define the path of the link + (path (cond + ((member type '("http" "https" "ftp")) + (concat type ":" raw-path)) + ((and re-radio (string-match re-radio raw-path)) + (setq radiop t)) + ((equal type "mailto") + (concat type ":" raw-path)) + ((equal type "file") + (if (and (or (org-file-image-p (expand-file-name raw-path)) + (string-match "\\.eps$" raw-path)) + (equal desc full-raw-path)) + (setq imgp t) + (progn (when (string-match "\\(.+\\)::.+" raw-path) + (setq raw-path (match-string 1 raw-path))) + (if (file-exists-p raw-path) + (concat type "://" (expand-file-name raw-path)) + (concat type "://" (org-export-directory + :LaTeX org-export-latex-options-plist) + raw-path)))))))) + ;; process with link inserting + (apply 'delete-region remove) + (cond ((and imgp (plist-get org-export-latex-options-plist :inline-images)) + (insert (format "\\includegraphics[%s]{%s}" + ;; image option should be set be a comment line + org-export-latex-image-default-option + (expand-file-name raw-path)))) + (radiop (insert (format "\\hyperref[%s]{%s}" raw-path desc))) + (path (insert (format "\\href{%s}{%s}" path desc))) + (t (insert "\\texttt{" desc "}"))))))) + +(defvar org-latex-entities) ; defined below + +(defun org-export-latex-cleaned-string () + "Clean stuff in the LaTeX export." + + ;; Preserve line breaks + (goto-char (point-min)) + (while (re-search-forward "\\\\\\\\" nil t) + (add-text-properties (match-beginning 0) (match-end 0) + '(org-protected t))) + + ;; Convert LaTeX to \LaTeX{} + (goto-char (point-min)) + (let ((case-fold-search nil) rpl) + (while (re-search-forward "\\([^+_]\\)LaTeX" nil t) + (replace-match (org-export-latex-protect-string + (concat (match-string 1) "\\LaTeX{}")) t t))) + + ;; Convert horizontal rules + (goto-char (point-min)) + (while (re-search-forward "^----+.$" nil t) + (replace-match (org-export-latex-protect-string "\\hrule") t t)) + + ;; Protect LaTeX commands like \commad[...]{...} or \command{...} + (goto-char (point-min)) + (while (re-search-forward "\\\\[a-zA-Z]+\\(?:\\[.*\\]\\)?{.*}" nil t) + (add-text-properties (match-beginning 0) (match-end 0) + '(org-protected t))) + + ;; Protect LaTeX entities + (goto-char (point-min)) + (while (re-search-forward (regexp-opt org-latex-entities) nil t) + (add-text-properties (match-beginning 0) (match-end 0) + '(org-protected t))) + + ;; Replace radio links + (goto-char (point-min)) + (while (re-search-forward + (concat "<<>>?\\((INVISIBLE)\\)?") nil t) + (replace-match + (org-export-latex-protect-string + (format "\\label{%s}%s"(match-string 1) + (if (match-string 2) "" (match-string 1)))) t t)) + + ;; Delete @<...> constructs + ;; Thanks to Daniel Clemente for this regexp + (goto-char (point-min)) + (while (re-search-forward "@<\\(?:[^\"\n]\\|\".*\"\\)*?>" nil t) + (replace-match "")) + + ;; When converting to LaTeX, replace footnotes + ;; FIXME: don't protect footnotes from conversion + (when (plist-get org-export-latex-options-plist :footnotes) + (goto-char (point-min)) + (while (re-search-forward "\\[[0-9]+\\]" nil t) + (when (save-match-data + (save-excursion (beginning-of-line) + (looking-at "[^:|#]"))) + (let ((foot-beg (match-beginning 0)) + (foot-end (match-end 0)) + (foot-prefix (match-string 0)) + footnote footnote-rpl) + (save-excursion + (when (search-forward foot-prefix nil t) + (replace-match "") + (let ((end (save-excursion + (if (re-search-forward "^$\\|^#.*$\\|\\[[0-9]+\\]" nil t) + (match-beginning 0) (point-max))))) + (setq footnote (concat (org-trim (buffer-substring (point) end)) + " ")) ; prevent last } being part of a link + (delete-region (point) end)) + (goto-char foot-beg) + (delete-region foot-beg foot-end) + (unless (null footnote) + (setq footnote-rpl (format "\\footnote{%s}" footnote)) + (add-text-properties 0 10 '(org-protected t) footnote-rpl) + (add-text-properties (1- (length footnote-rpl)) + (length footnote-rpl) + '(org-protected t) footnote-rpl) + (insert footnote-rpl))))))) + + ;; Replace footnote section tag for LaTeX + (goto-char (point-min)) + (while (re-search-forward + (concat "^" footnote-section-tag-regexp) nil t) + (replace-match "")))) + +;;; List handling: + +(defun org-export-latex-lists () + "Replace plain text lists in current buffer into LaTeX lists." + "Convert lists to LaTeX." + (goto-char (point-min)) + (while (re-search-forward org-export-latex-list-beginning-re nil t) + (beginning-of-line) + (insert (org-list-to-latex (org-list-parse-list t)) "\n"))) + +(defun org-list-parse-list (&optional delete) + "Parse the list at point. +Return a list containing first level items as strings and +sublevels as a list of strings." + (let ((start (org-list-item-begin)) + (end (org-list-end)) + output itemsep) + (while (re-search-forward org-export-latex-list-beginning-re end t) + (setq itemsep (if (save-match-data + (string-match "^[0-9]" (match-string 2))) + "[0-9]+\\(?:\\.\\|)\\)" "[-+]")) + (let* ((indent1 (match-string 1)) + (nextitem (save-excursion + (save-match-data + (or (and (re-search-forward + (concat "^" indent1 itemsep " *?") end t) + (match-beginning 0)) end)))) + (item (buffer-substring + (point) + (or (and (re-search-forward + org-export-latex-list-beginning-re end t) + (goto-char (match-beginning 0))) + (goto-char end)))) + (nextindent (match-string 1)) + (item (org-trim item)) + (item (if (string-match "^\\[.+\\]" item) + (replace-match "\\\\texttt{\\&}" + t nil item) item))) + (push item output) + (when (> (length nextindent) + (length indent1)) + (narrow-to-region (point) nextitem) + (push (org-list-parse-list) output) + (widen)))) + (when delete (delete-region start end)) + (setq output (nreverse output)) + (push (if (string-match "^\\[0" itemsep) + 'ordered 'unordered) output))) + +(defun org-list-item-begin () + "Find the beginning of the list item and return its position." + (save-excursion + (if (not (or (looking-at org-export-latex-list-beginning-re) + (re-search-backward + org-export-latex-list-beginning-re nil t))) + (progn (goto-char (point-min)) (point)) + (match-beginning 0)))) + +(defun org-list-end () + "Find the end of the list and return its position." + (save-excursion + (catch 'exit + (while (or (looking-at org-export-latex-list-beginning-re) + (looking-at "^[ \t]+\\|^$")) + (if (eq (point) (point-max)) + (throw 'exit (point-max))) + (forward-line 1))) (point))) + +(defun org-list-insert-radio-list () + "Insert a radio list template appropriate for this major mode." + (interactive) + (let* ((e (assq major-mode org-list-radio-list-templates)) + (txt (nth 1 e)) + name pos) + (unless e (error "No radio list setup defined for %s" major-mode)) + (setq name (read-string "List name: ")) + (while (string-match "%n" txt) + (setq txt (replace-match name t t txt))) + (or (bolp) (insert "\n")) + (setq pos (point)) + (insert txt) + (goto-char pos))) + +(defun org-list-send-list (&optional maybe) + "Send a tranformed version of this list to the receiver position. +With argument MAYBE, fail quietly if no transformation is defined for +this list." + (interactive) + (catch 'exit + (unless (org-at-item-p) (error "Not at a list")) + (save-excursion + (goto-char (org-list-item-begin)) + (beginning-of-line 0) + (unless (looking-at "#\\+ORGLST: *SEND +\\([a-zA-Z0-9_]+\\) +\\([^ \t\r\n]+\\)\\( +.*\\)?") + (if maybe + (throw 'exit nil) + (error "Don't know how to transform this list")))) + (let* ((name (match-string 1)) + beg + (transform (intern (match-string 2))) + (txt (buffer-substring-no-properties + (org-list-item-begin) + (org-list-end))) + (list (org-list-parse-list))) + (unless (fboundp transform) + (error "No such transformation function %s" transform)) + (setq txt (funcall transform list)) + ;; Find the insertion place + (save-excursion + (goto-char (point-min)) + (unless (re-search-forward + (concat "BEGIN RECEIVE ORGLST +" name "\\([ \t]\\|$\\)") nil t) + (error "Don't know where to insert translated list")) + (goto-char (match-beginning 0)) + (beginning-of-line 2) + (setq beg (point)) + (unless (re-search-forward (concat "END RECEIVE ORGLST +" name) nil t) + (error "Cannot find end of insertion region")) + (beginning-of-line 1) + (delete-region beg (point)) + (goto-char beg) + (insert txt "\n")) + (message "List converted and installed at receiver location")))) + +(defun org-list-to-generic (list params) + "Convert a LIST parsed through `org-list-parse-list' to other formats. + +Valid parameters are + +:ustart String to start an unordered list +:uend String to end an unordered list + +:ostart String to start an ordered list +:oend String to end an ordered list + +:splice When set to t, return only list body lines, don't wrap + them into :[u/o]start and :[u/o]end. Default is nil. + +:istart String to start a list item +:iend String to end a list item +:isep String to separate items +:lsep String to separate sublists" + (interactive) + (let* ((p params) sublist + (splicep (plist-get p :splice)) + (ostart (plist-get p :ostart)) + (oend (plist-get p :oend)) + (ustart (plist-get p :ustart)) + (uend (plist-get p :uend)) + (istart (plist-get p :istart)) + (iend (plist-get p :iend)) + (isep (plist-get p :isep)) + (lsep (plist-get p :lsep))) + (let ((wrapper + (cond ((eq (car list) 'ordered) + (concat ostart "\n%s" oend "\n")) + ((eq (car list) 'unordered) + (concat ustart "\n%s" uend "\n")))) + rtn) + (while (setq sublist (pop list)) + (cond ((symbolp sublist) nil) + ((stringp sublist) + (setq rtn (concat rtn istart sublist iend isep))) + (t + (setq rtn (concat rtn ;; previous list + lsep ;; list separator + (org-list-to-generic sublist p) + lsep ;; list separator + ))))) + (format wrapper rtn)))) + +(defun org-list-to-latex (list) + "Convert LIST into a LaTeX list." + (org-list-to-generic + list '(:splicep nil :ostart "\\begin{enumerate}" :oend "\\end{enumerate}" + :ustart "\\begin{itemize}" :uend "\\end{itemize}" + :istart "\\item " :iend "" + :isep "\n" :lsep "\n"))) + +(defun org-list-to-html (list) + "Convert LIST into a HTML list." + (org-list-to-generic + list '(:splicep nil :ostart "
    " :oend "
" + :ustart "
    " :uend "
" + :istart "
  • " :iend "
  • " + :isep "\n" :lsep "\n"))) + +(defun org-list-to-texinfo (list) + "Convert LIST into a Texinfo list." + (org-list-to-generic + list '(:splicep nil :ostart "@itemize @minus" :oend "@end itemize" + :ustart "@enumerate" :uend "@end enumerate" + :istart "@item\n" :iend "" + :isep "\n" :lsep "\n"))) + +(defconst org-latex-entities + '("\\!" + "\\'" + "\\+" + "\\," + "\\-" + "\\:" + "\\;" + "\\<" + "\\=" + "\\>" + "\\Huge" + "\\LARGE" + "\\Large" + "\\Styles" + "\\\\" + "\\`" + "\\addcontentsline" + "\\address" + "\\addtocontents" + "\\addtocounter" + "\\addtolength" + "\\addvspace" + "\\alph" + "\\appendix" + "\\arabic" + "\\author" + "\\begin{array}" + "\\begin{center}" + "\\begin{description}" + "\\begin{enumerate}" + "\\begin{eqnarray}" + "\\begin{equation}" + "\\begin{figure}" + "\\begin{flushleft}" + "\\begin{flushright}" + "\\begin{itemize}" + "\\begin{list}" + "\\begin{minipage}" + "\\begin{picture}" + "\\begin{quotation}" + "\\begin{quote}" + "\\begin{tabbing}" + "\\begin{table}" + "\\begin{tabular}" + "\\begin{thebibliography}" + "\\begin{theorem}" + "\\begin{titlepage}" + "\\begin{verbatim}" + "\\begin{verse}" + "\\bf" + "\\bf" + "\\bibitem" + "\\bigskip" + "\\cdots" + "\\centering" + "\\circle" + "\\cite" + "\\cleardoublepage" + "\\clearpage" + "\\cline" + "\\closing" + "\\dashbox" + "\\date" + "\\ddots" + "\\dotfill" + "\\em" + "\\fbox" + "\\flushbottom" + "\\fnsymbol" + "\\footnote" + "\\footnotemark" + "\\footnotesize" + "\\footnotetext" + "\\frac" + "\\frame" + "\\framebox" + "\\hfill" + "\\hline" + "\\hrulespace" + "\\hspace" + "\\huge" + "\\hyphenation" + "\\include" + "\\includeonly" + "\\indent" + "\\input" + "\\it" + "\\kill" + "\\label" + "\\large" + "\\ldots" + "\\line" + "\\linebreak" + "\\linethickness" + "\\listoffigures" + "\\listoftables" + "\\location" + "\\makebox" + "\\maketitle" + "\\mark" + "\\mbox" + "\\medskip" + "\\multicolumn" + "\\multiput" + "\\newcommand" + "\\newcounter" + "\\newenvironment" + "\\newfont" + "\\newlength" + "\\newline" + "\\newpage" + "\\newsavebox" + "\\newtheorem" + "\\nocite" + "\\nofiles" + "\\noindent" + "\\nolinebreak" + "\\nopagebreak" + "\\normalsize" + "\\onecolumn" + "\\opening" + "\\oval" + "\\overbrace" + "\\overline" + "\\pagebreak" + "\\pagenumbering" + "\\pageref" + "\\pagestyle" + "\\par" + "\\parbox" + "\\put" + "\\raggedbottom" + "\\raggedleft" + "\\raggedright" + "\\raisebox" + "\\ref" + "\\rm" + "\\roman" + "\\rule" + "\\savebox" + "\\sc" + "\\scriptsize" + "\\setcounter" + "\\setlength" + "\\settowidth" + "\\sf" + "\\shortstack" + "\\signature" + "\\sl" + "\\small" + "\\smallskip" + "\\sqrt" + "\\tableofcontents" + "\\telephone" + "\\thanks" + "\\thispagestyle" + "\\tiny" + "\\title" + "\\tt" + "\\twocolumn" + "\\typein" + "\\typeout" + "\\underbrace" + "\\underline" + "\\usebox" + "\\usecounter" + "\\value" + "\\vdots" + "\\vector" + "\\verb" + "\\vfill" + "\\vline" + "\\vspace") + "A list of LaTeX commands to be protected when performing conversion.") + +(provide 'org-export-latex) + +;; arch-tag: 23c2b87d-da04-4c2d-ad2d-1eb6487bc3ad +;;; org-export-latex.el ends here diff --git a/lisp/textmodes/org-irc.el b/lisp/textmodes/org-irc.el new file mode 100644 index 00000000000..d880eda9b4d --- /dev/null +++ b/lisp/textmodes/org-irc.el @@ -0,0 +1,228 @@ +;;; org-irc.el --- Store links to IRC sessions + +;; Copyright (C) 2008 Free Software Foundation, Inc. + +;; Author: Philip Jackson +;; Keywords: erc, irc, link, org +;; Version: 1.3 + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Link to an IRC session. Only ERC has been implemented at the +;; moment. +;; +;; This file is loaded by default whenever org.el is loaded. Please +;; customize the variable `org-default-extensions' to select extensions +;; you would like to use, and to deselect those which you don't want. +;; +;; Please note that at the moment only ERC is supported. Other clients +;; shouldn't be diffficult to add though. +;; +;; Then set `org-irc-link-to-logs' to non-nil if you would like a +;; file:/ type link to be created to the current line in the logs or +;; to t if you would like to create an irc:/ style link. +;; +;; Links within an org buffer might look like this: +;; +;; [[irc:/irc.freenode.net/#emacs/bob][chat with bob in #emacs on freenode]] +;; [[irc:/irc.freenode.net/#emacs][#emacs on freenode]] +;; [[irc:/irc.freenode.net/]] +;; +;; If, when the resulting link is visited, there is no connection to a +;; requested server then one will be created. + +;;; Code: + +(require 'org) +(require 'erc) +(require 'erc-log) + +(defvar org-irc-client 'erc + "The IRC client to act on") +(defvar org-irc-link-to-logs nil + "non-nil will store a link to the logs, nil will store an irc: style link") + +(defvar erc-default-port) ; dynamically scoped from erc.el +(defvar erc-session-port) ; dynamically scoped form erc-backend.el +(defvar erc-server-announced-name) ; dynamically scoped form erc-backend.el + +;; Generic functions/config (extend these for other clients) + +(add-to-list 'org-store-link-functions + 'org-irc-store-link) + +(org-add-link-type "irc" 'org-irc-visit nil) + +(defun org-irc-visit (link) + "Dispatch to the correct visit function based on the client" + (let ((link (org-irc-parse-link link))) + (cond + ((eq org-irc-client 'erc) + (org-irc-visit-erc link)) + (t + (error "erc only known client"))))) + +(defun org-irc-parse-link (link) + "Get a of irc link attributes where `link' looks like +server:port/chan/user (port, chan and user being optional)." + (let* ((parts (split-string link "/" t)) + (len (length parts))) + (when (or (< len 1) (> len 3)) + (error "Failed to parse link needed 1-3 parts, got %d." len)) + (setcar parts (split-string (car parts) ":" t)) + parts)) + +;;;###autoload +(defun org-irc-store-link () + "Dispatch to the appropreate function to store a link to +something IRC related" + (cond + ((eq major-mode 'erc-mode) + (org-irc-erc-store-link)))) + +(defun org-irc-elipsify-description (string &optional after) + "Strip starting and ending whitespace and replace any chars +that appear after the value in `after' with '...'" + (let* ((after (number-to-string (or after 30))) + (replace-map (list (cons "^[ \t]*" "") + (cons "[ \t]*$" "") + (cons (concat "^\\(.\\{" after + "\\}\\).*") "\\1...")))) + (mapc (lambda (x) + (when (string-match (car x) string) + (setq string (replace-match (cdr x) nil nil string)))) + replace-map) + string)) + +;; ERC specific functions + +(defun org-irc-erc-get-line-from-log (erc-line) + "Find the most suitable line to link to from the erc logs. If +the user is on the erc-prompt then search backward for the first +non-blank line, otherwise return the current line. The result is +a cons of the filename and search string." + (erc-save-buffer-in-logs) + (with-current-buffer (find-file-noselect (erc-current-logfile)) + (goto-char (point-max)) + (list + (abbreviate-file-name buffer-file-name) + ;; can we get a '::' part? + (if (string= erc-line (erc-prompt)) + (progn + (goto-char (point-at-bol)) + (when (search-backward-regexp "^[^ ]" nil t) + (buffer-substring-no-properties (point-at-bol) + (point-at-eol)))) + (when (search-backward erc-line nil t) + (buffer-substring-no-properties (point-at-bol) + (point-at-eol))))))) + +(defun org-irc-erc-store-link () + "Depending on the variable `org-irc-link-to-logs' store either +a link to the log file for the current session or an irc: link to +the session itself." + (if org-irc-link-to-logs + (let* ((erc-line (buffer-substring-no-properties + (point-at-bol) (point-at-eol))) + (parsed-line (org-irc-erc-get-line-from-log erc-line))) + (if (erc-logging-enabled nil) + (progn + (org-store-link-props + :type "file" + :description (concat "'" (org-irc-elipsify-description + (cadr parsed-line) 20) + "' from an IRC conversation") + :link (concat "file:" (car parsed-line) "::" + (cadr parsed-line))) + t) + (error "This ERC session is not being logged"))) + (let* ((link-text (org-irc-get-erc-link)) + (link (org-irc-parse-link link-text))) + (if link-text + (progn + (org-store-link-props + :type "irc" + :link (org-make-link "irc:/" link-text) + :description (concat "irc session '" link-text "'") + :server (car (car link)) + :port (or (cadr (pop link)) erc-default-port) + :nick (pop link)) + t) + (error "Failed to create ('irc:/' style) ERC link"))))) + +(defun org-irc-get-erc-link () + "Return an org compatible irc:/ link from an ERC buffer" + (let ((link (concat erc-server-announced-name ":" + (number-to-string erc-session-port)))) + (concat link "/" + (if (and (erc-default-target) + (erc-channel-p (erc-default-target)) + (car (get-text-property (point) 'erc-data))) + ;; we can get a nick + (let ((nick (car (get-text-property (point) 'erc-data)))) + (concat (erc-default-target) "/" nick)) + (erc-default-target))))) + +(defun org-irc-visit-erc (link) + "Visit an ERC buffer based on criteria from the followed link" + (let* ((server (car (car link))) + (port (or (cadr (pop link)) erc-default-port)) + (server-buffer) + (buffer-list + (erc-buffer-filter + (lambda nil + (let ((tmp-server-buf (erc-server-buffer))) + (and tmp-server-buf + (with-current-buffer tmp-server-buf + (and + (string= erc-session-port port) + (string= erc-server-announced-name server) + (setq server-buffer tmp-server-buf))))))))) + (if buffer-list + (let ((chan-name (pop link))) + ;; if we got a channel name then switch to it or join it + (if chan-name + (let ((chan-buf (catch 'found + (dolist (x buffer-list) + (if (string= (buffer-name x) chan-name) + (throw 'found x)))))) + (if chan-buf + (progn + (switch-to-buffer chan-buf) + ;; if we got a nick, and they're in the chan, + ;; then start a chat with them + (let ((nick (pop link))) + (when nick + (if (member nick (erc-get-server-nickname-list)) + (progn + (goto-char (point-max)) + (insert (concat nick ": "))) + (error "%s not found in %s" nick chan-name))))) + (progn + (switch-to-buffer server-buffer) + (erc-cmd-JOIN chan-name)))) + (switch-to-buffer server-buffer))) + ;; no server match, make new connection + (erc-select :server server :port port)))) + +(provide 'org-irc) + +;; arch-tag: 018d7dda-53b8-4a35-ba92-6670939e525a +;;; org-irc.el ends here diff --git a/lisp/textmodes/org-mac-message.el b/lisp/textmodes/org-mac-message.el new file mode 100644 index 00000000000..c1cb5e58d27 --- /dev/null +++ b/lisp/textmodes/org-mac-message.el @@ -0,0 +1,78 @@ +;;; org-mac-message.el --- Support for links to Apple Mail messages by Message-ID + +;; Copyright (C) 2008 Free Software Foundation, Inc. + +;; Author: John Wiegley +;; Version: 1.2 +;; Keywords: outlines, hypermedia, calendar, wp + +;; This file is part of GNU Emacs. + +;; Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Code: + +(require 'org) + +(org-add-link-type "message" 'org-mac-message-open) + +(unless (fboundp 'do-applescript) + ;; Need to fake this using shell-command-to-string + (defun do-applescript (script) + (let (start cmd return) + (while (string-match "\n" script) + (setq script (replace-match "\r" t t script))) + (while (string-match "'" script start) + (setq start (+ 2 (match-beginning 0)) + script (replace-match "\\'" t t script))) + (setq cmd (concat "osascript -e '" script "'")) + (setq return (shell-command-to-string cmd)) + (concat "\"" (org-trim return) "\"")))) + +(defun org-mac-message-open (message-id) + "Visit the message with the given Message-ID. +This will use the command `open' with the message url." + (start-process (concat "open message:" message-id) nil + "open" (concat "message://<" (substring message-id 2) ">"))) + +(defun org-mac-message-insert-link () + "Insert a link to the messages currently selected in Apple Mail. +This will use applescript to get the message-id and the subject of the +active mail in AppleMail and make a link out of it." + (interactive) + (insert (org-mac-message-get-link))) + +(defun org-mac-message-get-link () + "Insert a link to the messages currently selected in Apple Mail. +This will use applescript to get the message-id and the subject of the +active mail in AppleMail and make a link out of it." + (let ((subject (do-applescript "tell application \"Mail\" + set theMessages to selection + subject of beginning of theMessages +end tell")) + (message-id (do-applescript "tell application \"Mail\" + set theMessages to selection + message id of beginning of theMessages +end tell"))) + (org-make-link-string + (concat "message://" + (substring message-id 1 (1- (length message-id)))) + (substring subject 1 (1- (length subject)))))) + +(provide 'org-mac-message) + +;; arch-tag: 3806d0c1-abe1-4db6-9c31-f3ed7d4a9b32 +;;; org-mac-message.el ends here diff --git a/lisp/textmodes/org-mouse.el b/lisp/textmodes/org-mouse.el new file mode 100644 index 00000000000..52770899f70 --- /dev/null +++ b/lisp/textmodes/org-mouse.el @@ -0,0 +1,1110 @@ +;;; org-mouse.el --- Better mouse support for org-mode + +;; Copyright (C) 2006, 2007, 2008 Free Software Foundation +;; +;; Author: Piotr Zielinski +;; Maintainer: Carsten Dominik +;; Version: 5.23 +;; +;; This file is part of GNU Emacs. +;; +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Org-mouse provides mouse support for org-mode. +;; +;; http://orgmode.org +;; +;; Org-mouse implements the following features: +;; * following links with the left mouse button (in Emacs 22) +;; * subtree expansion/collapse (org-cycle) with the left mouse button +;; * several context menus on the right mouse button: +;; + general text +;; + headlines +;; + timestamps +;; + priorities +;; + links +;; + tags +;; * promoting/demoting/moving subtrees with mouse-3 +;; + if the drag starts and ends in the same line then promote/demote +;; + otherwise move the subtree +;; +;; Use +;; --- +;; +;; To use this package, put the following line in your .emacs: +;; +;; (require 'org-mouse) +;; + +;; Fixme: +;; + deal with folding / unfolding issues + +;; TODO (This list is only theoretical, if you'd like to have some +;; feature implemented or a bug fix please send me an email, even if +;; something similar appears in the list below. This will help me get +;; the priorities right.): +;; +;; + org-store-link, insert link +;; + org tables +;; + occur with the current word/tag (same menu item) +;; + ctrl-c ctrl-c, for example, renumber the current list +;; + internal links + +;; Please email the maintainer with new feature suggestions / bugs + +;; History: +;; +;; SInce version 5.10: Changes are listed in the general org-mode docs. +;; +;; Version 5.09 +;; + Version number synchronization with Org-mode. +;; +;; Version 0.25 +;; + made compatible with org-mode 4.70 (thanks to Carsten for the patch) +;; +;; Version 0.24 +;; + minor changes to the table menu +;; +;; Version 0.23 +;; + preliminary support for tables and calculation marks +;; + context menu support for org-agenda-undo & org-sort-entries +;; +;; Version 0.22 +;; + handles undo support for the agenda buffer (requires org-mode >=4.58) +;; +;; Version 0.21 +;; + selected text activates its context menu +;; + shift-middleclick or right-drag inserts the text from the clipboard in the form of a link +;; +;; Version 0.20 +;; + the new "TODO Status" submenu replaces the "Cycle TODO" menu item +;; + the TODO menu can now list occurrences of a specific TODO keyword +;; + #+STARTUP line is now recognized +;; +;; Version 0.19 +;; + added support for dragging URLs to the org-buffer +;; +;; Version 0.18 +;; + added support for agenda blocks +;; +;; Version 0.17 +;; + toggle checkboxes with a single click +;; +;; Version 0.16 +;; + added support for checkboxes +;; +;; Version 0.15 +;; + org-mode now works with the Agenda buffer as well +;; +;; Version 0.14 +;; + added a menu option that converts plain list items to outline items +;; +;; Version 0.13 +;; + "Insert Heading" now inserts a sibling heading if the point is +;; on "***" and a child heading otherwise +;; +;; Version 0.12 +;; + compatible with Emacs 21 +;; + custom agenda commands added to the main menu +;; + moving trees should now work between windows in the same frame +;; +;; Version 0.11 +;; + fixed org-mouse-at-link (thanks to Carsten) +;; + removed [follow-link] bindings +;; +;; Version 0.10 +;; + added a menu option to remove highlights +;; + compatible with org-mode 4.21 now +;; +;; Version 0.08: +;; + trees can be moved/promoted/demoted by dragging with the right +;; mouse button (mouse-3) +;; + small changes in the above function +;; +;; Versions 0.01 -- 0.07: (I don't remember) + +(eval-when-compile (require 'cl)) +(require 'org) + +(defvar org-mouse-plain-list-regexp "\\([ \t]*\\)\\([-+*]\\|[0-9]+[.)]\\) " + "Regular expression that matches a plain list.") +(defvar org-mouse-direct t + "Internal variable indicating whether the current action is direct. + +If t, then the current action has been invoked directly through the buffer +it is intended to operate on. If nil, then the action has been invoked +indirectly, for example, through the agenda buffer.") + +(defgroup org-mouse nil + "Mouse support for org-mode." + :tag "Org Mouse" + :group 'org) + +(defcustom org-mouse-punctuation ":" + "Punctuation used when inserting text by drag and drop." + :group 'org-mouse + :type 'string) + + +(defun org-mouse-re-search-line (regexp) + "Search the current line for a given regular expression." + (beginning-of-line) + (re-search-forward regexp (point-at-eol) t)) + +(defun org-mouse-end-headline () + "Go to the end of current headline (ignoring tags)." + (interactive) + (end-of-line) + (skip-chars-backward "\t ") + (when (looking-back ":[A-Za-z]+:") + (skip-chars-backward ":A-Za-z") + (skip-chars-backward "\t "))) + +(defvar org-mouse-context-menu-function nil + "Function to create the context menu. +The value of this variable is the function invoked by +`org-mouse-context-menu' as the context menu.") +(make-variable-buffer-local 'org-mouse-context-menu-function) + +(defun org-mouse-show-context-menu (event prefix) + "Invoke the context menu. + +If the value of `org-mouse-context-menu-function' is a function, then +this function is called. Otherwise, the current major mode menu is used." + (interactive "@e \nP") + (if (and (= (event-click-count event) 1) + (or (not mark-active) + (sit-for (/ double-click-time 1000.0)))) + (progn + (select-window (posn-window (event-start event))) + (when (not (org-mouse-mark-active)) + (goto-char (posn-point (event-start event))) + (when (not (eolp)) (save-excursion (run-hooks 'post-command-hook))) + (let ((redisplay-dont-pause t)) + (sit-for 0))) + (if (functionp org-mouse-context-menu-function) + (funcall org-mouse-context-menu-function event) + (mouse-major-mode-menu event prefix))) + (setq this-command 'mouse-save-then-kill) + (mouse-save-then-kill event))) + + +(defun org-mouse-line-position () + "Returns `:beginning' or `:middle' or `:end', depending on the point position. + +If the point is at the end of the line, return `:end'. +If the point is separated from the beginning of the line only by white +space and *'s (`org-mouse-bolp'), return `:beginning'. Otherwise, +return `:middle'." + (cond + ((eolp) :end) + ((org-mouse-bolp) :beginning) + (t :middle))) + +(defun org-mouse-empty-line () + "Return non-nil iff the line contains only white space." + (save-excursion (beginning-of-line) (looking-at "[ \t]*$"))) + +(defun org-mouse-next-heading () + "Go to the next heading. +If there is none, ensure that the point is at the beginning of an empty line." + (unless (outline-next-heading) + (beginning-of-line) + (unless (org-mouse-empty-line) + (end-of-line) + (newline)))) + +(defun org-mouse-insert-heading () + "Insert a new heading, as `org-insert-heading'. + +If the point is at the :beginning (`org-mouse-line-position') of the line, +insert the new heading before the current line. Otherwise, insert it +after the current heading." + (interactive) + (case (org-mouse-line-position) + (:beginning (beginning-of-line) + (org-insert-heading)) + (t (org-mouse-next-heading) + (org-insert-heading)))) + +(defun org-mouse-timestamp-today (&optional shift units) + "Change the timestamp into SHIFT UNITS in the future. + +For the acceptable UNITS, see `org-timestamp-change'." + (interactive) + (flet ((org-read-date (&rest rest) (current-time))) + (org-time-stamp nil)) + (when shift + (org-timestamp-change shift units))) + +(defun org-mouse-keyword-menu (keywords function &optional selected itemformat) + "A helper function. + +Returns a menu fragment consisting of KEYWORDS. When a keyword +is selected by the user, FUNCTION is called with the selected +keyword as the only argument. + +If SELECTED is nil, then all items are normal menu items. If +SELECTED is a function, then each item is a checkbox, which is +enabled for a given keyword iff (funcall SELECTED keyword) return +non-nil. If SELECTED is neither nil nor a function, then the +items are radio buttons. A radio button is enabled for the +keyword `equal' to SELECTED. + +ITEMFORMAT governs formatting of the elements of KEYWORDS. If it +is a function, it is invoked with the keyword as the only +argument. If it is a string, it is interpreted as the format +string to (format ITEMFORMAT keyword). If it is neither a string +nor a function, elements of KEYWORDS are used directly. " + (mapcar + `(lambda (keyword) + (vector (cond + ((functionp ,itemformat) (funcall ,itemformat keyword)) + ((stringp ,itemformat) (format ,itemformat keyword)) + (t keyword)) + (list 'funcall ,function keyword) + :style (cond + ((null ,selected) t) + ((functionp ,selected) 'toggle) + (t 'radio)) + :selected (if (functionp ,selected) + (and (funcall ,selected keyword) t) + (equal ,selected keyword)))) + keywords)) + +(defun org-mouse-remove-match-and-spaces () + "Remove the match, make just one space around the point." + (interactive) + (replace-match "") + (just-one-space)) + +(defvar rest) +(defun org-mouse-replace-match-and-surround (newtext &optional fixedcase + literal string subexp) + "The same as `replace-match', but surrounds the replacement with spaces." + (apply 'replace-match rest) + (save-excursion + (goto-char (match-beginning (or subexp 0))) + (just-one-space) + (goto-char (match-end (or subexp 0))) + (just-one-space))) + + +(defun org-mouse-keyword-replace-menu (keywords &optional group itemformat + nosurround) + "A helper function. + +Returns a menu fragment consisting of KEYWORDS. When a keyword +is selected, group GROUP of the current match is replaced by the +keyword. The method ensures that both ends of the replacement +are separated from the rest of the text in the buffer by +individual spaces (unless NOSURROND is non-nil). + +The final entry of the menu is always \"None\", which removes the +match. + +ITEMFORMAT governs formatting of the elements of KEYWORDS. If it +is a function, it is invoked with the keyword as the only +argument. If it is a string, it is interpreted as the format +string to (format ITEMFORMAT keyword). If it is neither a string +nor a function, elements of KEYWORDS are used directly. +" + (setq group (or group 0)) + (let ((replace (org-mouse-match-closure + (if nosurround 'replace-match + 'org-mouse-replace-match-and-surround)))) + (append + (org-mouse-keyword-menu + keywords + `(lambda (keyword) (funcall ,replace keyword t t nil ,group)) + (match-string group) + itemformat) + `(["None" org-mouse-remove-match-and-spaces + :style radio + :selected ,(not (member (match-string group) keywords))])))) + +(defun org-mouse-show-headlines () + "Change the visibility of the current org buffer to only show headlines." + (interactive) + (let ((this-command 'org-cycle) + (last-command 'org-cycle) + (org-cycle-global-status nil)) + (org-cycle '(4)) + (org-cycle '(4)))) + +(defun org-mouse-show-overview () + "Change visibility of current org buffer to first-level headlines only." + (interactive) + (let ((org-cycle-global-status nil)) + (org-cycle '(4)))) + +(defun org-mouse-set-priority (priority) + "Set the priority of the current headline to PRIORITY." + (flet ((read-char-exclusive () priority)) + (org-priority))) + +(defvar org-mouse-priority-regexp "\\[#\\([A-Z]\\)\\]" + "Regular expression matching the priority indicator. +Differs from `org-priority-regexp' in that it doesn't contain the +leading '.*?'.") + +(defun org-mouse-get-priority (&optional default) + "Return the priority of the current headline. +DEFAULT is returned if no priority is given in the headline." + (save-excursion + (if (org-mouse-re-search-line org-mouse-priority-regexp) + (match-string 1) + (when default (char-to-string org-default-priority))))) + +;; (defun org-mouse-at-link () +;; (and (eq (get-text-property (point) 'face) 'org-link) +;; (save-excursion +;; (goto-char (previous-single-property-change (point) 'face)) +;; (or (looking-at org-bracket-link-regexp) +;; (looking-at org-angle-link-re) +;; (looking-at org-plain-link-re))))) + + +(defun org-mouse-delete-timestamp () + "Deletes the current timestamp as well as the preceding keyword. +SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:" + (when (or (org-at-date-range-p) (org-at-timestamp-p)) + (replace-match "") ; delete the timestamp + (skip-chars-backward " :A-Z") + (when (looking-at " *[A-Z][A-Z]+:") + (replace-match "")))) + +(defun org-mouse-looking-at (regexp skipchars &optional movechars) + (save-excursion + (let ((point (point))) + (if (looking-at regexp) t + (skip-chars-backward skipchars) + (forward-char (or movechars 0)) + (when (looking-at regexp) + (> (match-end 0) point)))))) + +(defun org-mouse-priority-list () + (loop for priority from ?A to org-lowest-priority + collect (char-to-string priority))) + +(defun org-mouse-tag-menu () ;todo + (append + (let ((tags (org-split-string (org-get-tags) ":"))) + (org-mouse-keyword-menu + (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp) + `(lambda (tag) + (org-mouse-set-tags + (sort (if (member tag (quote ,tags)) + (delete tag (quote ,tags)) + (cons tag (quote ,tags))) + 'string-lessp))) + `(lambda (tag) (member tag (quote ,tags))) + )) + '("--" + ["Align Tags Here" (org-set-tags nil t) t] + ["Align Tags in Buffer" (org-set-tags t t) t] + ["Set Tags ..." (org-set-tags) t]))) + + + +(defun org-mouse-set-tags (tags) + (save-excursion + ;; remove existing tags first + (beginning-of-line) + (when (org-mouse-re-search-line ":\\(\\([A-Za-z_]+:\\)+\\)") + (replace-match "")) + + ;; set new tags if any + (when tags + (end-of-line) + (insert " :" (mapconcat 'identity tags ":") ":") + (org-set-tags nil t)))) + +(defun org-mouse-insert-checkbox () + (interactive) + (and (org-at-item-p) + (goto-char (match-end 0)) + (unless (org-at-item-checkbox-p) + (delete-horizontal-space) + (insert " [ ] ")))) + +(defun org-mouse-agenda-type (type) + (case type + ('tags "Tags: ") + ('todo "TODO: ") + ('tags-tree "Tags tree: ") + ('todo-tree "TODO tree: ") + ('occur-tree "Occur tree: ") + (t "Agenda command ???"))) + + +(defun org-mouse-list-options-menu (alloptions &optional function) + (let ((options (save-match-data + (split-string (match-string-no-properties 1))))) + (print options) + (loop for name in alloptions + collect + (vector name + `(progn + (replace-match + (mapconcat 'identity + (sort (if (member ',name ',options) + (delete ',name ',options) + (cons ',name ',options)) + 'string-lessp) + " ") + nil nil nil 1) + (when (functionp ',function) (funcall ',function))) + :style 'toggle + :selected (and (member name options) t))))) + +(defun org-mouse-clip-text (text maxlength) + (if (> (length text) maxlength) + (concat (substring text 0 (- maxlength 3)) "...") + text)) + +(defun org-mouse-popup-global-menu () + (popup-menu + `("Main Menu" + ["Show Overview" org-mouse-show-overview t] + ["Show Headlines" org-mouse-show-headlines t] + ["Show All" show-all t] + ["Remove Highlights" org-remove-occur-highlights + :visible org-occur-highlights] + "--" + ["Check Deadlines" + (if (functionp 'org-check-deadlines-and-todos) + (org-check-deadlines-and-todos org-deadline-warning-days) + (org-check-deadlines org-deadline-warning-days)) t] + ["Check TODOs" org-show-todo-tree t] + ("Check Tags" + ,@(org-mouse-keyword-menu + (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp) + '(lambda (tag) (org-tags-sparse-tree nil tag))) + "--" + ["Custom Tag ..." org-tags-sparse-tree t]) + ["Check Phrase ..." org-occur] + "--" + ["Display Agenda" org-agenda-list t] + ["Display Timeline" org-timeline t] + ["Display TODO List" org-todo-list t] + ("Display Tags" + ,@(org-mouse-keyword-menu + (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp) + '(lambda (tag) (org-tags-view nil tag))) + "--" + ["Custom Tag ..." org-tags-view t]) + ["Display Calendar" org-goto-calendar t] + "--" + ,@(org-mouse-keyword-menu + (mapcar 'car org-agenda-custom-commands) + '(lambda (key) + (eval `(flet ((read-char-exclusive () (string-to-char ,key))) + (org-agenda nil)))) + nil + '(lambda (key) + (let ((entry (assoc key org-agenda-custom-commands))) + (org-mouse-clip-text + (cond + ((stringp (nth 1 entry)) (nth 1 entry)) + ((stringp (nth 2 entry)) + (concat (org-mouse-agenda-type (nth 1 entry)) + (nth 2 entry))) + (t "Agenda Command '%s'")) + 30)))) + "--" + ["Delete Blank Lines" delete-blank-lines + :visible (org-mouse-empty-line)] + ["Insert Checkbox" org-mouse-insert-checkbox + :visible (and (org-at-item-p) (not (org-at-item-checkbox-p)))] + ["Insert Checkboxes" + (org-mouse-for-each-item 'org-mouse-insert-checkbox) + :visible (and (org-at-item-p) (not (org-at-item-checkbox-p)))] + ["Plain List to Outline" org-mouse-transform-to-outline + :visible (org-at-item-p)]))) + + +(defun org-mouse-get-context (contextlist context) + (let ((contextdata (assq context contextlist))) + (when contextdata + (save-excursion + (goto-char (second contextdata)) + (re-search-forward ".*" (third contextdata)))))) + +(defun org-mouse-for-each-item (function) + (save-excursion + (ignore-errors + (while t (org-previous-item))) + (ignore-errors + (while t + (funcall function) + (org-next-item))))) + +(defun org-mouse-bolp () + "Returns true if there only spaces, tabs, and '*', between the beginning of line and the point" + (save-excursion + (skip-chars-backward " \t*") (bolp))) + +(defun org-mouse-insert-item (text) + (case (org-mouse-line-position) + (:beginning ; insert before + (beginning-of-line) + (looking-at "[ \t]*") + (open-line 1) + (indent-to (- (match-end 0) (match-beginning 0))) + (insert "+ ")) + + (:middle ; insert after + (end-of-line) + (newline t) + (indent-relative) + (insert "+ ")) + + (:end ; insert text here + (skip-chars-backward " \t") + (kill-region (point) (point-at-eol)) + (unless (looking-back org-mouse-punctuation) + (insert (concat org-mouse-punctuation " "))))) + + (insert text) + (beginning-of-line)) + +(defadvice dnd-insert-text (around org-mouse-dnd-insert-text activate) + (if (eq major-mode 'org-mode) + (org-mouse-insert-item text) + ad-do-it)) + +(defadvice dnd-open-file (around org-mouse-dnd-open-file activate) + (if (eq major-mode 'org-mode) + (org-mouse-insert-item uri) + ad-do-it)) + +(defun org-mouse-match-closure (function) + (let ((match (match-data t))) + `(lambda (&rest rest) + (save-match-data + (set-match-data ',match) + (apply ',function rest))))) + +(defun org-mouse-todo-keywords () + (if (boundp 'org-todo-keywords-1) org-todo-keywords-1 org-todo-keywords)) + +(defun org-mouse-match-todo-keyword () + (save-excursion + (org-back-to-heading) + (if (looking-at outline-regexp) (goto-char (match-end 0))) + (or (looking-at (concat " +" org-todo-regexp " *")) + (looking-at " \\( *\\)")))) + +(defun org-mouse-yank-link (click) + (interactive "e") + ;; Give temporary modes such as isearch a chance to turn off. + (run-hooks 'mouse-leave-buffer-hook) + (mouse-set-point click) + (setq mouse-selection-click-count 0) + (delete-horizontal-space) + (insert-for-yank (concat " [[" (current-kill 0) "]] "))) + +(defun org-mouse-context-menu (&optional event) + (let ((stamp-prefixes (list org-deadline-string org-scheduled-string)) + (contextlist (org-context))) + (flet ((get-context (context) (org-mouse-get-context contextlist context))) + (cond + ((org-mouse-mark-active) + (let ((region-string (buffer-substring (region-beginning) (region-end)))) + (popup-menu + `(nil + ["Sparse Tree" (org-occur ',region-string)] + ["Find in Buffer" (occur ',region-string)] + ["Grep in Current Dir" + (grep (format "grep -rnH -e '%s' *" ',region-string))] + ["Grep in Parent Dir" + (grep (format "grep -rnH -e '%s' ../*" ',region-string))] + "--" + ["Convert to Link" + (progn (save-excursion (goto-char (region-beginning)) (insert "[[")) + (save-excursion (goto-char (region-end)) (insert "]]")))] + ["Insert Link Here" (org-mouse-yank-link ',event)])))) + + ((save-excursion (beginning-of-line) (looking-at "#\\+STARTUP: \\(.*\\)")) + (popup-menu + `(nil + ,@(org-mouse-list-options-menu (mapcar 'car org-startup-options) + 'org-mode-restart)))) + ((or (eolp) + (and (looking-at "\\( \\|\t\\)\\(+:[0-9a-zA-Z_:]+\\)?\\( \\|\t\\)+$") + (looking-back " \\|\t"))) + (org-mouse-popup-global-menu)) + ((get-context :checkbox) + (popup-menu + '(nil + ["Toggle" org-toggle-checkbox t] + ["Remove" org-mouse-remove-match-and-spaces t] + "" + ["All Clear" (org-mouse-for-each-item + (lambda () + (when (save-excursion (org-at-item-checkbox-p)) + (replace-match "[ ]"))))] + ["All Set" (org-mouse-for-each-item + (lambda () + (when (save-excursion (org-at-item-checkbox-p)) + (replace-match "[X]"))))] + ["All Toggle" (org-mouse-for-each-item 'org-toggle-checkbox) t] + ["All Remove" (org-mouse-for-each-item + (lambda () + (when (save-excursion (org-at-item-checkbox-p)) + (org-mouse-remove-match-and-spaces))))] + ))) + ((and (org-mouse-looking-at "\\b\\w+" "a-zA-Z0-9_") + (member (match-string 0) (org-mouse-todo-keywords))) + (popup-menu + `(nil + ,@(org-mouse-keyword-replace-menu (org-mouse-todo-keywords)) + "--" + ["Check TODOs" org-show-todo-tree t] + ["List all TODO keywords" org-todo-list t] + [,(format "List only %s" (match-string 0)) + (org-todo-list (match-string 0)) t] + ))) + ((and (org-mouse-looking-at "\\b[A-Z]+:" "A-Z") + (member (match-string 0) stamp-prefixes)) + (popup-menu + `(nil + ,@(org-mouse-keyword-replace-menu stamp-prefixes) + "--" + ["Check Deadlines" org-check-deadlines t] + ))) + ((org-mouse-looking-at org-mouse-priority-regexp "[]A-Z#") ; priority + (popup-menu `(nil ,@(org-mouse-keyword-replace-menu + (org-mouse-priority-list) 1 "Priority %s" t)))) + ((get-context :link) + (popup-menu + '(nil + ["Open" org-open-at-point t] + ["Open in Emacs" (org-open-at-point t) t] + "--" + ["Copy link" (kill-new (match-string 0))] + ["Cut link" + (progn + (kill-region (match-beginning 0) (match-end 0)) + (just-one-space))] + "--" + ["Grep for TODOs" + (grep (format "grep -nH -i 'todo\\|fixme' %s*" (match-string 2)))] +; ["Paste file link" ((insert "file:") (yank))] + ))) + ((org-mouse-looking-at ":\\([A-Za-z0-9_]+\\):" "A-Za-z0-9_" -1) ;tags + (popup-menu + `(nil + [,(format "Display '%s'" (match-string 1)) + (org-tags-view nil ,(match-string 1))] + [,(format "Sparse Tree '%s'" (match-string 1)) + (org-tags-sparse-tree nil ,(match-string 1))] + "--" + ,@(org-mouse-tag-menu)))) + ((org-at-timestamp-p) + (popup-menu + '(nil + ["Show Day" org-open-at-point t] + ["Change Timestamp" org-time-stamp t] + ["Delete Timestamp" (org-mouse-delete-timestamp) t] + ["Compute Time Range" org-evaluate-time-range (org-at-date-range-p)] + "--" + ["Set for Today" org-mouse-timestamp-today] + ["Set for Tomorrow" (org-mouse-timestamp-today 1 'day)] + ["Set in 1 Week" (org-mouse-timestamp-today 7 'day)] + ["Set in 2 Weeks" (org-mouse-timestamp-today 14 'day)] + ["Set in a Month" (org-mouse-timestamp-today 1 'month)] + "--" + ["+ 1 Day" (org-timestamp-change 1 'day)] + ["+ 1 Week" (org-timestamp-change 7 'day)] + ["+ 1 Month" (org-timestamp-change 1 'month)] + "--" + ["- 1 Day" (org-timestamp-change -1 'day)] + ["- 1 Week" (org-timestamp-change -7 'day)] + ["- 1 Month" (org-timestamp-change -1 'month)]))) + ((get-context :table-special) + (let ((mdata (match-data))) + (incf (car mdata) 2) + (store-match-data mdata)) + (message "match: %S" (match-string 0)) + (popup-menu `(nil ,@(org-mouse-keyword-replace-menu + '(" " "!" "^" "_" "$" "#" "*" "'") 0 + (lambda (mark) + (case (string-to-char mark) + (? "( ) Nothing Special") + (?! "(!) Column Names") + (?^ "(^) Field Names Above") + (?_ "(^) Field Names Below") + (?$ "($) Formula Parameters") + (?# "(#) Recalculation: Auto") + (?* "(*) Recalculation: Manual") + (?' "(') Recalculation: None"))) t)))) + ((assq :table contextlist) + (popup-menu + '(nil + ["Align Table" org-ctrl-c-ctrl-c] + ["Blank Field" org-table-blank-field] + ["Edit Field" org-table-edit-field] + "--" + ("Column" + ["Move Column Left" org-metaleft] + ["Move Column Right" org-metaright] + ["Delete Column" org-shiftmetaleft] + ["Insert Column" org-shiftmetaright] + "--" + ["Enable Narrowing" (setq org-table-limit-column-width (not org-table-limit-column-width)) :selected org-table-limit-column-width :style toggle]) + ("Row" + ["Move Row Up" org-metaup] + ["Move Row Down" org-metadown] + ["Delete Row" org-shiftmetaup] + ["Insert Row" org-shiftmetadown] + ["Sort lines in region" org-table-sort-lines (org-at-table-p)] + "--" + ["Insert Hline" org-table-insert-hline]) + ("Rectangle" + ["Copy Rectangle" org-copy-special] + ["Cut Rectangle" org-cut-special] + ["Paste Rectangle" org-paste-special] + ["Fill Rectangle" org-table-wrap-region]) + "--" + ["Set Column Formula" org-table-eval-formula] + ["Set Field Formula" (org-table-eval-formula '(4))] + ["Edit Formulas" org-table-edit-formulas] + "--" + ["Recalculate Line" org-table-recalculate] + ["Recalculate All" (org-table-recalculate '(4))] + ["Iterate All" (org-table-recalculate '(16))] + "--" + ["Toggle Recalculate Mark" org-table-rotate-recalc-marks] + ["Sum Column/Rectangle" org-table-sum + :active (or (org-at-table-p) (org-region-active-p))] + ["Field Info" org-table-field-info] + ["Debug Formulas" + (setq org-table-formula-debug (not org-table-formula-debug)) + :style toggle :selected org-table-formula-debug] + ))) + ((and (assq :headline contextlist) (not (eolp))) + (let ((priority (org-mouse-get-priority t))) + (popup-menu + `("Headline Menu" + ("Tags and Priorities" + ,@(org-mouse-keyword-menu + (org-mouse-priority-list) + '(lambda (keyword) + (org-mouse-set-priority (string-to-char keyword))) + priority "Priority %s") + "--" + ,@(org-mouse-tag-menu)) + ("TODO Status" + ,@(progn (org-mouse-match-todo-keyword) + (org-mouse-keyword-replace-menu (org-mouse-todo-keywords) + 1))) + ["Show Tags" + (with-current-buffer org-mouse-main-buffer (org-agenda-show-tags)) + :visible (not org-mouse-direct)] + ["Show Priority" + (with-current-buffer org-mouse-main-buffer (org-agenda-show-priority)) + :visible (not org-mouse-direct)] + ,@(if org-mouse-direct '("--") nil) + ["New Heading" org-mouse-insert-heading :visible org-mouse-direct] + ["Set Deadline" + (progn (org-mouse-end-headline) (insert " ") (org-deadline)) + :active (not (save-excursion + (org-mouse-re-search-line org-deadline-regexp)))] + ["Schedule Task" + (progn (org-mouse-end-headline) (insert " ") (org-schedule)) + :active (not (save-excursion + (org-mouse-re-search-line org-scheduled-regexp)))] + ["Insert Timestamp" + (progn (org-mouse-end-headline) (insert " ") (org-time-stamp nil)) t] +; ["Timestamp (inactive)" org-time-stamp-inactive t] + "--" + ["Archive Subtree" org-archive-subtree] + ["Cut Subtree" org-cut-special] + ["Copy Subtree" org-copy-special] + ["Paste Subtree" org-paste-special :visible org-mouse-direct] + ("Sort Children" + ["Alphabetically" (org-sort-entries nil ?a)] + ["Numerically" (org-sort-entries nil ?n)] + ["By Time/Date" (org-sort-entries nil ?t)] + "--" + ["Reverse Alphabetically" (org-sort-entries nil ?A)] + ["Reverse Numerically" (org-sort-entries nil ?N)] + ["Reverse By Time/Date" (org-sort-entries nil ?T)]) + "--" + ["Move Trees" org-mouse-move-tree :active nil] + )))) + (t + (org-mouse-popup-global-menu)))))) + +;; (defun org-mouse-at-regexp (regexp) +;; (save-excursion +;; (let ((point (point)) +;; (bol (progn (beginning-of-line) (point))) +;; (eol (progn (end-of-line) (point)))) +;; (goto-char point) +;; (re-search-backward regexp bol 1) +;; (and (not (eolp)) +;; (progn (forward-char) +;; (re-search-forward regexp eol t)) +;; (<= (match-beginning 0) point))))) + +(defun org-mouse-mark-active () + (and mark-active transient-mark-mode)) + +(defun org-mouse-in-region-p (pos) + (and (org-mouse-mark-active) + (>= pos (region-beginning)) + (< pos (region-end)))) + +(defun org-mouse-down-mouse (event) + (interactive "e") + (setq this-command last-command) + (unless (and (= 1 (event-click-count event)) + (org-mouse-in-region-p (posn-point (event-start event)))) + (mouse-drag-region event))) + +(add-hook 'org-mode-hook + '(lambda () + (setq org-mouse-context-menu-function 'org-mouse-context-menu) + +; (define-key org-mouse-map [follow-link] 'mouse-face) + (define-key org-mouse-map (if (featurep 'xemacs) [button3] [mouse-3]) nil) + (define-key org-mode-map [mouse-3] 'org-mouse-show-context-menu) + (define-key org-mode-map [down-mouse-1] 'org-mouse-down-mouse) + (define-key org-mouse-map [C-drag-mouse-1] 'org-mouse-move-tree) + (define-key org-mouse-map [C-down-mouse-1] 'org-mouse-move-tree-start) + (define-key org-mode-map [S-mouse-2] 'org-mouse-yank-link) + (define-key org-mode-map [drag-mouse-3] 'org-mouse-yank-link) + (define-key org-mouse-map [drag-mouse-3] 'org-mouse-move-tree) + (define-key org-mouse-map [down-mouse-3] 'org-mouse-move-tree-start) + + (font-lock-add-keywords nil + `((,outline-regexp + 0 `(face org-link mouse-face highlight keymap ,org-mouse-map) + 'prepend) + ("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +" + (1 `(face org-link keymap ,org-mouse-map mouse-face highlight) 'prepend)) + ("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[ X]\\]\\)" + (2 `(face bold keymap ,org-mouse-map mouse-face highlight) t))) + t) + + (defadvice org-open-at-point (around org-mouse-open-at-point activate) + (let ((context (org-context))) + (cond + ((assq :headline-stars context) (org-cycle)) + ((assq :checkbox context) (org-toggle-checkbox)) + ((assq :item-bullet context) + (let ((org-cycle-include-plain-lists t)) (org-cycle))) + (t ad-do-it)))))) + +(defun org-mouse-move-tree-start (event) + (interactive "e") + (message "Same line: promote/demote, (***):move before, (text): make a child")) + + +(defun org-mouse-make-marker (position) + (with-current-buffer (window-buffer (posn-window position)) + (copy-marker (posn-point position)))) + +(defun org-mouse-move-tree (event) + ;; todo: handle movements between different buffers + (interactive "e") + (save-excursion + (let* ((start (org-mouse-make-marker (event-start event))) + (end (org-mouse-make-marker (event-end event))) + (sbuf (marker-buffer start)) + (ebuf (marker-buffer end))) + + (when (and sbuf ebuf) + (set-buffer sbuf) + (goto-char start) + (org-back-to-heading) + (if (and (eq sbuf ebuf) + (equal + (point) + (save-excursion (goto-char end) (org-back-to-heading) (point)))) + ;; if the same line then promote/demote + (if (>= end start) (org-demote-subtree) (org-promote-subtree)) + ;; if different lines then move + (org-cut-subtree) + + (set-buffer ebuf) + (goto-char end) + (org-back-to-heading) + (when (and (eq sbuf ebuf) + (equal + (point) + (save-excursion (goto-char start) + (org-back-to-heading) (point)))) + (outline-end-of-subtree) + (end-of-line) + (if (eobp) (newline) (forward-char))) + + (when (looking-at outline-regexp) + (let ((level (- (match-end 0) (match-beginning 0)))) + (when (> end (match-end 0)) + (outline-end-of-subtree) + (end-of-line) + (if (eobp) (newline) (forward-char)) + (setq level (1+ level))) + (org-paste-subtree level) + (save-excursion + (outline-end-of-subtree) + (when (bolp) (delete-char -1)))))))))) + + +(defun org-mouse-transform-to-outline () + (interactive) + (org-back-to-heading) + (let ((minlevel 1000) + (replace-text (concat (match-string 0) "* "))) + (beginning-of-line 2) + (save-excursion + (while (not (or (eobp) (looking-at outline-regexp))) + (when (looking-at org-mouse-plain-list-regexp) + (setq minlevel (min minlevel (- (match-end 1) (match-beginning 1))))) + (forward-line))) + (while (not (or (eobp) (looking-at outline-regexp))) + (when (and (looking-at org-mouse-plain-list-regexp) + (eq minlevel (- (match-end 1) (match-beginning 1)))) + (replace-match replace-text)) + (forward-line)))) + +(defvar _cmd) ;dynamically scoped from `org-with-remote-undo'. + +(defun org-mouse-do-remotely (command) +; (org-agenda-check-no-diary) + (when (get-text-property (point) 'org-marker) + (let* ((anticol (- (point-at-eol) (point))) + (marker (get-text-property (point) 'org-marker)) + (buffer (marker-buffer marker)) + (pos (marker-position marker)) + (hdmarker (get-text-property (point) 'org-hd-marker)) + (buffer-read-only nil) + (newhead "--- removed ---") + (org-mouse-direct nil) + (org-mouse-main-buffer (current-buffer))) + (when (eq (with-current-buffer buffer major-mode) 'org-mode) + (let ((endmarker (save-excursion + (set-buffer buffer) + (outline-end-of-subtree) + (forward-char 1) + (copy-marker (point))))) + (org-with-remote-undo buffer + (with-current-buffer buffer + (widen) + (goto-char pos) + (org-show-hidden-entry) + (save-excursion + (and (outline-next-heading) + (org-flag-heading nil))) ; show the next heading + (org-back-to-heading) + (setq marker (copy-marker (point))) + (goto-char (max (point-at-bol) (- (point-at-eol) anticol))) + (funcall command) + (message "_cmd: %S" _cmd) + (message "this-command: %S" this-command) + (unless (eq (marker-position marker) (marker-position endmarker)) + (setq newhead (org-get-heading)))) + + (beginning-of-line 1) + (save-excursion + (org-agenda-change-all-lines newhead hdmarker 'fixface)))) + t)))) + +(defun org-mouse-agenda-context-menu (&optional event) + (or (org-mouse-do-remotely 'org-mouse-context-menu) + (popup-menu + '("Agenda" + ("Agenda Files") + "--" + ["Undo" (progn (message "last command: %S" last-command) (setq this-command 'org-agenda-undo) (org-agenda-undo)) + :visible (if (eq last-command 'org-agenda-undo) + org-agenda-pending-undo-list + org-agenda-undo-list)] + ["Rebuild Buffer" org-agenda-redo t] + ["New Diary Entry" + org-agenda-diary-entry (org-agenda-check-type nil 'agenda 'timeline) t] + "--" + ["Goto Today" org-agenda-goto-today + (org-agenda-check-type nil 'agenda 'timeline) t] + ["Display Calendar" org-agenda-goto-calendar + (org-agenda-check-type nil 'agenda 'timeline) t] + ("Calendar Commands" + ["Phases of the Moon" org-agenda-phases-of-moon + (org-agenda-check-type nil 'agenda 'timeline)] + ["Sunrise/Sunset" org-agenda-sunrise-sunset + (org-agenda-check-type nil 'agenda 'timeline)] + ["Holidays" org-agenda-holidays + (org-agenda-check-type nil 'agenda 'timeline)] + ["Convert" org-agenda-convert-date + (org-agenda-check-type nil 'agenda 'timeline)] + "--" + ["Create iCalendar file" org-export-icalendar-combine-agenda-files t]) + "--" + ["Day View" org-agenda-day-view + :active (org-agenda-check-type nil 'agenda) + :style radio :selected (equal org-agenda-ndays 1)] + ["Week View" org-agenda-week-view + :active (org-agenda-check-type nil 'agenda) + :style radio :selected (equal org-agenda-ndays 7)] + "--" + ["Show Logbook entries" org-agenda-log-mode + :style toggle :selected org-agenda-show-log + :active (org-agenda-check-type nil 'agenda 'timeline)] + ["Include Diary" org-agenda-toggle-diary + :style toggle :selected org-agenda-include-diary + :active (org-agenda-check-type nil 'agenda)] + ["Use Time Grid" org-agenda-toggle-time-grid + :style toggle :selected org-agenda-use-time-grid + :active (org-agenda-check-type nil 'agenda)] + ["Follow Mode" org-agenda-follow-mode + :style toggle :selected org-agenda-follow-mode] + "--" + ["Quit" org-agenda-quit t] + ["Exit and Release Buffers" org-agenda-exit t] + )))) + +(defun org-mouse-get-gesture (event) + (let ((startxy (posn-x-y (event-start event))) + (endxy (posn-x-y (event-end event)))) + (if (< (car startxy) (car endxy)) :right :left))) + + +; (setq org-agenda-mode-hook nil) +(add-hook 'org-agenda-mode-hook + '(lambda () + (setq org-mouse-context-menu-function 'org-mouse-agenda-context-menu) + (define-key org-agenda-keymap + (if (featurep 'xemacs) [button3] [mouse-3]) + 'org-mouse-show-context-menu) + (define-key org-agenda-keymap [down-mouse-3] 'org-mouse-move-tree-start) + (define-key org-agenda-keymap [C-mouse-4] 'org-agenda-earlier) + (define-key org-agenda-keymap [C-mouse-5] 'org-agenda-later) + (define-key org-agenda-keymap [drag-mouse-3] + '(lambda (event) (interactive "e") + (case (org-mouse-get-gesture event) + (:left (org-agenda-earlier 1)) + (:right (org-agenda-later 1))))))) + +(provide 'org-mouse) + +;; arch-tag: ff1ae557-3529-41a3-95c6-baaebdcc280f diff --git a/lisp/textmodes/org-publish.el b/lisp/textmodes/org-publish.el new file mode 100644 index 00000000000..aa75a60d358 --- /dev/null +++ b/lisp/textmodes/org-publish.el @@ -0,0 +1,655 @@ +;;; org-publish.el --- publish related org-mode files as a website + +;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. + +;; Author: David O'Toole +;; Maintainer: Bastien Guerry +;; Keywords: hypermedia, outlines, wp +;; Version: 5.23a + +;; This file is part of GNU Emacs. +;; +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Requires at least version 4.27 of org.el + +;; This program allow configurable publishing of related sets of +;; Org-mode files as a complete website. +;; +;; org-publish.el can do the following: +;; +;; + Publish all one's org-files to HTML or LaTeX +;; + Upload HTML, images, attachments and other files to a web server +;; + Exclude selected private pages from publishing +;; + Publish a clickable index of pages +;; + Manage local timestamps for publishing only changed files +;; + Accept plugin functions to extend range of publishable content +;; +;; Special thanks to the org-mode maintainer Carsten Dominik for his +;; ideas, enthusiasm, and cooperation. + +;;; Installation: + +;; Put org-publish.el in your load path, byte-compile it, and then add +;; the following lines to your emacs initialization file: + +;; (autoload 'org-publish "org-publish" nil t) +;; (autoload 'org-publish "org-publish-all" nil t) +;; (autoload 'org-publish "org-publish-current-file" nil t) +;; (autoload 'org-publish "org-publish-current-project" nil t) + +;; NOTE: When org-publish.el is included with org.el, those forms are +;; already in the file org-install.el, and hence don't need to be put +;; in your emacs initialization file in this case. + +;;; Usage: +;; +;; The program's main configuration variable is +;; `org-publish-project-alist'. See below for example configurations +;; with commentary. + +;; The main interactive functions are: +;; +;; M-x org-publish +;; M-x org-publish-all +;; M-x org-publish-current-file +;; M-x org-publish-current-project + +;;;; Simple example configuration: + +;; (setq org-publish-project-alist +;; (list +;; '("org" . (:base-directory "~/org/" +;; :base-extension "org" +;; :publishing-directory "~/public_html" +;; :with-section-numbers nil +;; :table-of-contents nil +;; :recursive t +;; :style ""))) + +;;;; More complex example configuration: + +;; Imagine your *.org files are kept in ~/org, your images in +;; ~/images, and stylesheets in ~/other. Now imagine you want to +;; publish the files through an ssh connection to a remote host, via +;; Tramp-mode. To maintain relative links from *.org files to /images +;; and /other, we should replicate the same directory structure in +;; your web server account's designated html root (in this case, +;; assumed to be ~/html) + +;; Once you've done created the proper directories, you can adapt the +;; following example configuration to your specific paths, run M-x +;; org-publish-all, and it should publish the files to the correct +;; directories on the web server, transforming the *.org files into +;; HTML, and leaving other files alone. + +;; (setq org-publish-project-alist +;; (list +;; '("orgfiles" :base-directory "~/org/" +;; :base-extension "org" +;; :publishing-directory "/ssh:user@host:~/html/notebook/" +;; :publishing-function org-publish-org-to-html +;; :exclude "PrivatePage.org" ;; regexp +;; :headline-levels 3 +;; :with-section-numbers nil +;; :table-of-contents nil +;; :style "" +;; :auto-preamble t +;; :auto-postamble nil) +;; ("images" :base-directory "~/images/" +;; :base-extension "jpg\\|gif\\|png" +;; :publishing-directory "/ssh:user@host:~/html/images/" +;; :publishing-function org-publish-attachment) +;; ("other" :base-directory "~/other/" +;; :base-extension "css" +;; :publishing-directory "/ssh:user@host:~/html/other/" +;; :publishing-function org-publish-attachment) +;; ("website" :components ("orgfiles" "images" "other")))) + +;; For more information, see the documentation for the variable +;; `org-publish-project-alist'. + +;; Of course, you don't have to publish to remote directories from +;; within emacs. You can always just publish to local folders, and +;; then use the synchronization/upload tool of your choice. + +;;; List of user-visible changes since version 1.27 + +;; 1.78: Allow list-valued :publishing-function +;; 1.77: Added :preparation-function, this allows you to use GNU Make etc. +;; 1.65: Remove old "composite projects". They're redundant. +;; 1.64: Allow meta-projects with :components +;; 1.57: Timestamps flag is now called "org-publish-use-timestamps-flag" +;; 1.52: Properly set default for :index-filename +;; 1.48: Composite projects allowed. +;; :include keyword allowed. +;; 1.43: Index no longer includes itself in the index. +;; 1.42: Fix "function definition is void" error +;; when :publishing-function not set in org-publish-current-file. +;; 1.41: Fixed bug where index isn't published on first try. +;; 1.37: Added interactive function "org-publish". Prompts for particular +;; project name to publish. +;; 1.34: Added force-publish option to all interactive functions. +;; 1.32: Fixed "index.org has changed on disk" error during index publishing. +;; 1.30: Fixed startup error caused by (require 'em-unix) + +;;; Code: + +(eval-when-compile + (require 'cl)) + +(require 'dired-aux) + +(defgroup org-publish nil + "Options for publishing a set of Org-mode and related files." + :tag "Org Publishing" + :group 'org) + +(defcustom org-publish-project-alist nil + "Association list to control publishing behavior. +Each element of the alist is a publishing 'project.' The CAR of +each element is a string, uniquely identifying the project. The +CDR of each element is in one of the following forms: + + (:property value :property value ... ) + +OR, + + (:components (\"project-1\" \"project-2\" ...)) + +When the CDR of an element of org-publish-project-alist is in +this second form, the elements of the list after :components are +taken to be components of the project, which group together files +requiring different publishing options. When you publish such a +project with M-x org-publish, the components all publish. + +When a property is given a value in org-publish-project-alist, its +setting overrides the value of the corresponding user variable + (if any) during publishing. However, options set within a file +override everything. + +Most properties are optional, but some should always be set: + + :base-directory Directory containing publishing source files + :base-extension Extension (without the dot!) of source files. + This can be a regular expression. + :publishing-directory Directory (possibly remote) where output + files will be published + +The :exclude property may be used to prevent certain files from +being published. Its value may be a string or regexp matching +file names you don't want to be published. + +The :include property may be used to include extra files. Its +value may be a list of filenames to include. The filenames are +considered relative to the publishing directory. + +When both :include and :exclude properties are given values, the +exclusion step happens first. + +One special property controls which back-end function to use for +publishing files in the project. This can be used to extend the +set of file types publishable by org-publish, as well as the set +of output formats. + + :publishing-function Function to publish file. The default is + org-publish-org-to-html, but other + values are possible. May also be a + list of functions, in which case + each function in the list is invoked + in turn. + +Another property allows you to insert code that prepares a +project for publishing. For example, you could call GNU Make on a +certain makefile, to ensure published files are built up to date. + + :preparation-function Function to be called before publishing + this project. + +Some properties control details of the Org publishing process, +and are equivalent to the corresponding user variables listed in +the right column. See the documentation for those variables to +learn more about their use and default values. + + :language org-export-default-language + :headline-levels org-export-headline-levels + :section-numbers org-export-with-section-numbers + :table-of-contents org-export-with-toc + :emphasize org-export-with-emphasize + :sub-superscript org-export-with-sub-superscripts + :TeX-macros org-export-with-TeX-macros + :fixed-width org-export-with-fixed-width + :tables org-export-with-tables + :table-auto-headline org-export-highlight-first-table-line + :style org-export-html-style + :convert-org-links org-export-html-link-org-files-as-html + :inline-images org-export-html-inline-images + :expand-quoted-html org-export-html-expand + :timestamp org-export-html-with-timestamp + :publishing-directory org-export-publishing-directory + :preamble org-export-html-preamble + :postamble org-export-html-postamble + :auto-preamble org-export-html-auto-preamble + :auto-postamble org-export-html-auto-postamble + :author user-full-name + :email user-mail-address + +The following properties may be used to control publishing of an +index of files or summary page for a given project. + + :auto-index Whether to publish an index during + org-publish-current-project or org-publish-all. + :index-filename Filename for output of index. Defaults + to 'index.org' (which becomes 'index.html') + :index-title Title of index page. Defaults to name of file. + :index-function Plugin function to use for generation of index. + Defaults to 'org-publish-org-index', which + generates a plain list of links to all files + in the project." + :group 'org-publish + :type 'alist) + +(defcustom org-publish-use-timestamps-flag t + "When non-nil, use timestamp checking to publish only changed files. +When nil, do no timestamp checking and always publish all +files." + :group 'org-publish + :type 'boolean) + +(defcustom org-publish-timestamp-directory "~/.org-timestamps/" + "Name of directory in which to store publishing timestamps." + :group 'org-publish + :type 'directory) + +(defcustom org-publish-before-export-hook nil + "Hook run before export on the Org file. +If the functions in this hook modify the original Org buffer, the +modified buffer will be used for export, but the buffer will be +restored and saved back to its initial state after export." + :group 'org-publish + :type 'hook) + +(defcustom org-publish-after-export-hook nil + "Hook run after export on the exported buffer. +If functions in this hook modify the buffer, it will be saved." + :group 'org-publish + :type 'hook) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Timestamp-related functions + +(defun org-publish-timestamp-filename (filename) + "Return path to timestamp file for filename FILENAME." + (while (string-match + (if (eq system-type 'windows-nt) "~\\|/\\|:" "~\\|/") filename) + (setq filename (replace-match "_" nil t filename))) + (concat org-publish-timestamp-directory filename ".timestamp")) + +(defun org-publish-needed-p (filename) + "Return `t' if FILENAME should be published." + (if org-publish-use-timestamps-flag + (if (file-exists-p org-publish-timestamp-directory) + ;; first handle possible wrong timestamp directory + (if (not (file-directory-p org-publish-timestamp-directory)) + (error "Org publish timestamp: %s is not a directory" + org-publish-timestamp-directory) + ;; there is a timestamp, check if FILENAME is newer + (file-newer-than-file-p + filename (org-publish-timestamp-filename filename)))) + ;; don't use timestamps, always return t + t)) + +(defun org-publish-update-timestamp (filename) + "Update publishing timestamp for file FILENAME. +If there is no timestamp, create one." + (let ((timestamp-file (org-publish-timestamp-filename filename)) + newly-created-timestamp) + (if (not (file-exists-p timestamp-file)) + ;; create timestamp file if needed + (with-temp-buffer + (make-directory (file-name-directory timestamp-file) t) + (write-file timestamp-file) + (setq newly-created-timestamp t))) + ;; Emacs 21 doesn't have `set-file-times' + (if (and (fboundp 'set-file-times) + (not newly-created-timestamp)) + (set-file-times timestamp-file) + (call-process "touch" nil 0 nil timestamp-file)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mapping files to project names + +(defvar org-publish-files-alist nil + "Alist of files and their parent project. +Each element of this alist is of the form: + + (file-name . project-name)") + +(defun org-publish-initialize-files-alist (&optional refresh) + "Set `org-publish-files-alist' if it is not set. +Also set it if the optional argument REFRESH is non-nil." + (interactive "P") + (when (or refresh (not org-publish-files-alist)) + (setq org-publish-files-alist + (org-publish-get-files org-publish-project-alist)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Compatibility aliases + +;; Delete-dups is not in Emacs <22 +(if (fboundp 'delete-dups) + (defalias 'org-publish-delete-dups 'delete-dups) + (defun org-publish-delete-dups (list) + "Destructively remove `equal' duplicates from LIST. +Store the result in LIST and return it. LIST must be a proper list. +Of several `equal' occurrences of an element in LIST, the first +one is kept. + +This is a compatibility function for Emacsen without `delete-dups'." + ;; Code from `subr.el' in Emacs 22: + (let ((tail list)) + (while tail + (setcdr tail (delete (car tail) (cdr tail))) + (setq tail (cdr tail)))) + list)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Getting project information out of org-publish-project-alist + +(defun org-publish-get-files (projects-alist &optional no-exclusion) + "Return the list of all publishable files for PROJECTS-ALIST. +If NO-EXCLUSION is non-nil, don't exclude files." + (let (all-files) + ;; add all projects + (mapc + (lambda(p) + (let* ((exclude (plist-get (cdr p) :exclude)) + (files (and p (org-publish-get-base-files p exclude)))) + ;; add all files from this project + (mapc (lambda(f) + (add-to-list 'all-files + (cons (expand-file-name f) (car p)))) + files))) + (org-publish-expand-projects projects-alist)) + all-files)) + +(defun org-publish-expand-projects (projects-alist) + "Expand projects contained in PROJECTS-ALIST." + (let (without-component with-component) + (mapc (lambda(p) + (add-to-list + (if (plist-get (cdr p) :components) + 'with-component 'without-component) p)) + projects-alist) + (org-publish-delete-dups + (append without-component + (car (mapcar (lambda(p) (org-publish-expand-components p)) + with-component)))))) + +(defun org-publish-expand-components (project) + "Expand PROJECT into an alist of its components." + (let* ((components (plist-get (cdr project) :components))) + (org-publish-delete-dups + (delq nil (mapcar (lambda(c) (assoc c org-publish-project-alist)) + components))))) + +(defun org-publish-get-base-files (project &optional exclude-regexp) + "Return a list of all files in PROJECT. +If EXCLUDE-REGEXP is set, this will be used to filter out +matching filenames." + (let* ((project-plist (cdr project)) + (base-dir (file-name-as-directory + (plist-get project-plist :base-directory))) + (include-list (plist-get project-plist :include)) + (recursive-p (plist-get project-plist :recursive)) + (extension (or (plist-get project-plist :base-extension) "org")) + (regexp (concat "^[^\\.].*\\.\\(" extension "\\)$")) + alldirs allfiles files dir) + ;; Get all files and directories in base-directory + (setq files (dired-files-attributes base-dir)) + ;; Get all subdirectories if recursive-p + (setq alldirs + (if recursive-p + (delq nil (mapcar (lambda(f) (if (caaddr f) (cadr f))) files)) + (list base-dir))) + (while (setq dir (pop alldirs)) + (setq files (directory-files dir t regexp)) + ;; Exclude files + (setq files + (if (not exclude-regexp) + files + (delq nil + (mapcar (lambda (x) + (if (string-match exclude-regexp x) nil x)) + files)))) + ;; Include extra files + (let (inc) + (while (setq inc (pop include-list)) + (setq files (cons (expand-file-name inc dir) files)))) + (setq allfiles (append allfiles files))) + allfiles)) + +(defun org-publish-get-project-from-filename (filename) + "Return the project FILENAME belongs." + (let* ((project-name (cdr (assoc (expand-file-name filename) + org-publish-files-alist)))) + (assoc project-name org-publish-project-alist))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Pluggable publishing back-end functions + +(defun org-publish-org-to (format plist filename pub-dir) + "Publish an org file to FORMAT. +PLIST is the property list for the given project. +FILENAME is the filename of the org file to be published. +PUB-DIR is the publishing directory." + (require 'org) + (unless (file-exists-p pub-dir) + (make-directory pub-dir t)) + (find-file filename) + (let ((init-buf (current-buffer)) + (init-point (point)) + (init-buf-string (buffer-string)) export-buf) + ;; run hooks before exporting + (run-hooks 'org-publish-before-export-hook) + ;; export the possibly modified buffer + (setq export-buf + (funcall (intern (concat "org-export-as-" format)) + (plist-get plist :headline-levels) + nil plist nil nil pub-dir)) + (set-buffer export-buf) + ;; run hooks after export and save export + (and (run-hooks 'org-publish-after-export-hook) + (if (buffer-modified-p) (save-buffer))) + ;; maybe restore buffer's content + (set-buffer init-buf) + (when (buffer-modified-p init-buf) + (erase-buffer) + (insert init-buf-string) + (save-buffer) + (goto-char init-point)))) + +(defun org-publish-org-to-latex (plist filename pub-dir) + "Publish an org file to LaTeX. +See `org-publish-org-to' to the list of arguments." + (org-publish-org-to "latex" plist filename pub-dir)) + +(defun org-publish-org-to-html (plist filename pub-dir) + "Publish an org file to HTML. +See `org-publish-org-to' to the list of arguments." + (org-publish-org-to "html" plist filename pub-dir)) + +(defun org-publish-attachment (plist filename pub-dir) + "Publish a file with no transformation of any kind. +See `org-publish-org-to' to the list of arguments." + ;; make sure eshell/cp code is loaded + (eval-and-compile + (require 'eshell) + (require 'esh-maint) + (require 'em-unix)) + (eshell/cp filename pub-dir)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Publishing files, sets of files, and indices + +(defun org-publish-file (filename &optional project) + "Publish file FILENAME from PROJECT." + (when (org-publish-needed-p filename) + (let* ((project + (or project + (or (org-publish-get-project-from-filename filename) + (if (y-or-n-p + (format "%s is not in a project. Re-read the list of projects files? " + (abbreviate-file-name filename))) + ;; If requested, re-initialize the list of projects files + (progn (org-publish-initialize-files-alist t) + (or (org-publish-get-project-from-filename filename) + (error "File %s not part of any known project" + (abbreviate-file-name filename)))) + (error "Can't publish file outside of a project"))))) + (project-plist (cdr project)) + (publishing-function + (or (plist-get project-plist :publishing-function) + 'org-publish-org-to-html)) + (base-dir (file-name-as-directory + (file-truename (plist-get project-plist :base-directory)))) + (pub-dir (file-name-as-directory + (file-truename (plist-get project-plist :publishing-directory)))) + tmp-pub-dir) + (setq tmp-pub-dir + (file-name-directory + (concat pub-dir + (and (string-match (regexp-quote base-dir) filename) + (substring filename (match-end 0)))))) + (if (listp publishing-function) + ;; allow chain of publishing functions + (mapc (lambda (f) + (funcall f project-plist filename tmp-pub-dir)) + publishing-function) + (funcall publishing-function project-plist filename tmp-pub-dir))) + (org-publish-update-timestamp filename))) + +(defun org-publish-projects (projects) + "Publish all files belonging to the PROJECTS alist. +If :auto-index is set, publish the index too." + (mapc + (lambda (project) + (let* ((project-plist (cdr project)) + (exclude-regexp (plist-get project-plist :exclude)) + (index-p (plist-get project-plist :auto-index)) + (index-filename (or (plist-get project-plist :index-filename) + "index.org")) + (index-function (or (plist-get project-plist :index-function) + 'org-publish-org-index)) + (preparation-function (plist-get project-plist :preparation-function)) + (files (org-publish-get-base-files project exclude-regexp)) file) + (when preparation-function (funcall preparation-function)) + (if index-p (funcall index-function project index-filename)) + (while (setq file (pop files)) + (org-publish-file file project)))) + (org-publish-expand-projects projects))) + +(defun org-publish-org-index (project &optional index-filename) + "Create an index of pages in set defined by PROJECT. +Optionally set the filename of the index with INDEX-FILENAME. +Default for INDEX-FILENAME is 'index.org'." + (let* ((project-plist (cdr project)) + (dir (file-name-as-directory + (plist-get project-plist :base-directory))) + (exclude-regexp (plist-get project-plist :exclude)) + (files (org-publish-get-base-files project exclude-regexp)) + (index-filename (concat dir (or index-filename "index.org"))) + (index-buffer (find-buffer-visiting index-filename)) + (ifn (file-name-nondirectory index-filename)) + file) + ;; if buffer is already open, kill it to prevent error message + (if index-buffer + (kill-buffer index-buffer)) + (with-temp-buffer + (while (setq file (pop files)) + (let ((fn (file-name-nondirectory file))) + ;; index shouldn't index itself + (unless (string= fn ifn) + (insert (concat " + [[file:" fn "][" + (file-name-sans-extension fn) + "]]\n"))))) + (write-file index-filename) + (kill-buffer (current-buffer))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Interactive publishing functions + +(defalias 'org-publish-project 'org-publish "Publish project.") + +;;;###autoload +(defun org-publish (project &optional force) + "Publish PROJECT." + (interactive "P") + (save-window-excursion + (let* ((force current-prefix-arg) + (org-publish-use-timestamps-flag + (if force nil org-publish-use-timestamps-flag))) + (org-publish-projects + (list (or project + (assoc (completing-read + "Publish project: " + org-publish-project-alist nil t) + org-publish-project-alist))))))) + +;;;###autoload +(defun org-publish-all (&optional force) + "Publish all projects. +With prefix argument, force publish all files." + (interactive "P") + (org-publish-initialize-files-alist) + (save-window-excursion + (let ((org-publish-use-timestamps-flag + (if force nil org-publish-use-timestamps-flag))) + (org-publish-projects org-publish-project-alist)))) + +;;;###autoload +(defun org-publish-current-file (&optional force) + "Publish the current file. +With prefix argument, force publish the file." + (interactive "P") + (org-publish-initialize-files-alist) + (save-window-excursion + (let ((org-publish-use-timestamps-flag + (if force nil org-publish-use-timestamps-flag))) + (org-publish-file (buffer-file-name))))) + +;;;###autoload +(defun org-publish-current-project (&optional force) + "Publish the project associated with the current file. +With a prefix argument, force publishing of all files in +the project." + (interactive "P") + (org-publish-initialize-files-alist) + (save-window-excursion + (let ((project (org-publish-get-project-from-filename (buffer-file-name))) + (org-publish-use-timestamps-flag + (if force nil org-publish-use-timestamps-flag))) + (if (not project) + (error "File %s is not part of any known project" (buffer-file-name))) + (org-publish project)))) + +(provide 'org-publish) + + +;; arch-tag: 72807f3c-8af0-4a6b-8dca-c3376eb25adb +;;; org-publish.el ends here diff --git a/lisp/textmodes/org.el b/lisp/textmodes/org.el index ea54cf74e3e..080615e4110 100644 --- a/lisp/textmodes/org.el +++ b/lisp/textmodes/org.el @@ -1,11 +1,11 @@ -;;;; org.el --- Outline-based notes management and organize +;;; org.el --- Outline-based notes management and organizer ;; Carstens outline-mode for keeping track of everything. ;; Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. ;; -;; Author: Carsten Dominik +;; Author: Carsten Dominik ;; Keywords: outlines, hypermedia, calendar, wp -;; Homepage: http://www.astro.uva.nl/~dominik/Tools/org/ -;; Version: 4.67d +;; Homepage: http://orgmode.org +;; Version: 5.23a ;; ;; This file is part of GNU Emacs. ;; @@ -49,7 +49,7 @@ ;; --------------------------- ;; See the corresponding sections in the manual at ;; -;; http://staff.science.uva.nl/~dominik/Tools/org/org.html#Installation +;; http://orgmode.org/org.html#Installation ;; ;; Documentation ;; ------------- @@ -60,7 +60,7 @@ ;; in the etc/ directory of Emacs 22. ;; ;; A list of recent changes can be found at -;; http://www.astro.uva.nl/~dominik/Tools/org/Changes +;; http://orgmode.org/Changes.html ;; ;;; Code: @@ -77,17 +77,24 @@ (require 'outline) (require 'noutline) ;; Other stuff we need. (require 'time-date) +(unless (fboundp 'time-subtract) (defalias 'time-subtract 'subtract-time)) (require 'easymenu) ;;;; Customization variables ;;; Version -(defvar org-version "4.67c" +(defconst org-version "5.23a" "The version number of the file org.el.") -(defun org-version () - (interactive) - (message "Org-mode version %s" org-version)) + +(defun org-version (&optional here) + "Show the org-mode version in the echo area. +With prefix arg HERE, insert it at point." + (interactive "P") + (let ((version (format "Org-mode version %s" org-version))) + (message version) + (if here + (insert version)))) ;;; Compatibility constants (defconst org-xemacs-p (featurep 'xemacs)) ; not used by org.el itself @@ -97,6 +104,44 @@ (get-text-property 0 'test (format "%s" x))) "Does format transport text properties?") +(defmacro org-bound-and-true-p (var) + "Return the value of symbol VAR if it is bound, else nil." + `(and (boundp (quote ,var)) ,var)) + +(defmacro org-unmodified (&rest body) + "Execute body without changing `buffer-modified-p'." + `(set-buffer-modified-p + (prog1 (buffer-modified-p) ,@body))) + +(defmacro org-re (s) + "Replace posix classes in regular expression." + (if (featurep 'xemacs) + (let ((ss s)) + (save-match-data + (while (string-match "\\[:alnum:\\]" ss) + (setq ss (replace-match "a-zA-Z0-9" t t ss))) + (while (string-match "\\[:alpha:\\]" ss) + (setq ss (replace-match "a-zA-Z" t t ss))) + ss)) + s)) + +(defmacro org-preserve-lc (&rest body) + `(let ((_line (org-current-line)) + (_col (current-column))) + (unwind-protect + (progn ,@body) + (goto-line _line) + (move-to-column _col)))) + +(defmacro org-without-partial-completion (&rest body) + `(let ((pc-mode (and (boundp 'partial-completion-mode) + partial-completion-mode))) + (unwind-protect + (progn + (if pc-mode (partial-completion-mode -1)) + ,@body) + (if pc-mode (partial-completion-mode 1))))) + ;;; The custom variables (defgroup org nil @@ -106,6 +151,41 @@ :group 'hypermedia :group 'calendar) +(defcustom org-load-hook nil + "Hook that is run after org.el has been loaded." + :group 'org + :type 'hook) + +;(defcustom org-default-extensions '(org-irc) +; "Extensions that should always be loaded together with org.el. +;If the description starts with , this means the extension +;will be autoloaded when needed, preloading is not necessary. +;FIXME: this does not ork correctly, ignore it for now." +; :group 'org +; :type +; '(set :greedy t +; (const :tag " Mouse support (org-mouse.el)" org-mouse) +; (const :tag " Publishing (org-publish.el)" org-publish) +; (const :tag " LaTeX export (org-export-latex.el)" org-export-latex) +; (const :tag " IRC/ERC links (org-irc.el)" org-irc) +; (const :tag " Apple Mail message links under OS X (org-mac-message.el)" org-mac-message))) +; +;(defun org-load-default-extensions () +; "Load all extensions listed in `org-default-extensions'." +; (mapc (lambda (ext) +; (condition-case nil (require ext) +; (error (message "Problems while trying to load feature `%s'" ext)))) +; org-default-extensions)) + +;(eval-after-load "org" '(org-load-default-extensions)) + +;; FIXME: Needs a separate group... +(defcustom org-completion-fallback-command 'hippie-expand + "The expansion command called by \\[org-complete] in normal context. +Normal means, no org-mode-specific context." + :group 'org + :type 'function) + (defgroup org-startup nil "Options concerning startup of Org-mode." :tag "Org Startup" @@ -153,21 +233,13 @@ has been set." :group 'org-startup :type 'boolean) -(defcustom org-CUA-compatible nil - "Non-nil means use alternative key bindings for S-. -Org-mode used S- for changing timestamps and priorities. -S- is also used for example by `CUA-mode' to select text. -If you want to use Org-mode together with `CUA-mode', Org-mode needs to use -alternative bindings. Setting this variable to t will replace the following -keys both in Org-mode and in the Org-agenda buffer. - -S-RET -> C-S-RET -S-up -> M-p -S-down -> M-n -S-left -> M-- -S-right -> M-+ - -If you do not like the alternative keys, take a look at the variable +(defcustom org-replace-disputed-keys nil + "Non-nil means use alternative key bindings for some keys. +Org-mode uses S- keys for changing timestamps and priorities. +These keys are also used by other packages like `CUA-mode' or `windmove.el'. +If you want to use Org-mode together with one of these other modes, +or more generally if you would like to move some Org-mode commands to +other keys, set this variable and configure the keys with the variable `org-disputed-keys'. This option is only relevant at load-time of Org-mode, and must be set @@ -176,30 +248,58 @@ become effective." :group 'org-startup :type 'boolean) -(defvar org-disputed-keys - '((S-up [(shift up)] [(meta ?p)]) - (S-down [(shift down)] [(meta ?n)]) - (S-left [(shift left)] [(meta ?-)]) - (S-right [(shift right)] [(meta ?+)]) - (S-return [(shift return)] [(control shift return)])) +(if (fboundp 'defvaralias) + (defvaralias 'org-CUA-compatible 'org-replace-disputed-keys)) + +(defcustom org-disputed-keys + '(([(shift up)] . [(meta p)]) + ([(shift down)] . [(meta n)]) + ([(shift left)] . [(meta -)]) + ([(shift right)] . [(meta +)]) + ([(control shift right)] . [(meta shift +)]) + ([(control shift left)] . [(meta shift -)])) "Keys for which Org-mode and other modes compete. -This is an alist, cars are symbols for lookup, 1st element is the default key, -second element will be used when `org-CUA-compatible' is t.") +This is an alist, cars are the default keys, second element specifies +the alternative to use when `org-replace-disputed-keys' is t. + +Keys can be specified in any syntax supported by `define-key'. +The value of this option takes effect only at Org-mode's startup, +therefore you'll have to restart Emacs to apply it after changing." + :group 'org-startup + :type 'alist) (defun org-key (key) - "Select a key according to `org-CUA-compatible'." - (nth (if org-CUA-compatible 2 1) - (or (assq key org-disputed-keys) - (error "Invalid Key %s in `org-key'" key)))) + "Select key according to `org-replace-disputed-keys' and `org-disputed-keys'. +Or return the original if not disputed." + (if org-replace-disputed-keys + (let* ((nkey (key-description key)) + (x (org-find-if (lambda (x) + (equal (key-description (car x)) nkey)) + org-disputed-keys))) + (if x (cdr x) key)) + key)) + +(defun org-find-if (predicate seq) + (catch 'exit + (while seq + (if (funcall predicate (car seq)) + (throw 'exit (car seq)) + (pop seq))))) + +(defun org-defkey (keymap key def) + "Define a key, possibly translated, as returned by `org-key'." + (define-key keymap (org-key key) def)) (defcustom org-ellipsis nil "The ellipsis to use in the Org-mode outline. When nil, just use the standard three dots. When a string, use that instead, -and just in Org-mode (which will then use its own display table). +When a face, use the standart 3 dots, but with the specified face. +The change affects only Org-mode (which will then use its own display table). Changing this requires executing `M-x org-mode' in a buffer to become effective." :group 'org-startup :type '(choice (const :tag "Default" nil) + (face :tag "Face" :value org-warning) (string :tag "String" :value "...#"))) (defvar org-display-table nil @@ -255,7 +355,8 @@ An entry can be toggled between QUOTE and normal with :group 'org-keywords :type 'string) -(defvar org-repeat-re "\\\n]*\\([.+]?\\+[0-9]+[dwmy]\\)" "Regular expression for specifying repeated events. After a match, group 1 contains the repeat expression.") @@ -269,6 +370,25 @@ After a match, group 1 contains the repeat expression.") :tag "Org Reveal Location" :group 'org-structure) +(defconst org-context-choice + '(choice + (const :tag "Always" t) + (const :tag "Never" nil) + (repeat :greedy t :tag "Individual contexts" + (cons + (choice :tag "Context" + (const agenda) + (const org-goto) + (const occur-tree) + (const tags-tree) + (const link-search) + (const mark-goto) + (const bookmark-jump) + (const isearch) + (const default)) + (boolean)))) + "Contexts for the reveal options.") + (defcustom org-show-hierarchy-above '((default . t)) "Non-nil means, show full hierarchy when revealing a location. Org-mode often shows locations in an org-mode file which might have @@ -287,24 +407,9 @@ contexts. Valid contexts are isearch when exiting from an incremental search default default for all contexts not set explicitly" :group 'org-reveal-location - :type '(choice - (const :tag "Always" t) - (const :tag "Never" nil) - (repeat :greedy t :tag "Individual contexts" - (cons - (choice :tag "Context" - (const agenda) - (const org-goto) - (const occur-tree) - (const tags-tree) - (const link-search) - (const mark-goto) - (const bookmark-jump) - (const isearch) - (const default)) - (boolean))))) + :type org-context-choice) -(defcustom org-show-following-heading '((default . t)) +(defcustom org-show-following-heading '((default . nil)) "Non-nil means, show following heading when revealing a location. Org-mode often shows locations in an org-mode file which might have been invisible before. When this is set, the heading following the @@ -315,22 +420,7 @@ use the command \\[org-reveal] to show more context. Instead of t, this can also be an alist specifying this option for different contexts. See `org-show-hierarchy-above' for valid contexts." :group 'org-reveal-location - :type '(choice - (const :tag "Always" t) - (const :tag "Never" nil) - (repeat :greedy t :tag "Individual contexts" - (cons - (choice :tag "Context" - (const agenda) - (const org-goto) - (const occur-tree) - (const tags-tree) - (const link-search) - (const mark-goto) - (const bookmark-jump) - (const isearch) - (const default)) - (boolean))))) + :type org-context-choice) (defcustom org-show-siblings '((default . nil) (isearch t)) "Non-nil means, show all sibling heading when revealing a location. @@ -346,29 +436,42 @@ use the command \\[org-reveal] to show more context. Instead of t, this can also be an alist specifying this option for different contexts. See `org-show-hierarchy-above' for valid contexts." :group 'org-reveal-location - :type '(choice - (const :tag "Always" t) - (const :tag "Never" nil) - (repeat :greedy t :tag "Individual contexts" - (cons - (choice :tag "Context" - (const agenda) - (const org-goto) - (const occur-tree) - (const tags-tree) - (const link-search) - (const mark-goto) - (const bookmark-jump) - (const isearch) - (const default)) - (boolean))))) + :type org-context-choice) + +(defcustom org-show-entry-below '((default . nil)) + "Non-nil means, show the entry below a headline when revealing a location. +Org-mode often shows locations in an org-mode file which might have +been invisible before. When this is set, the text below the headline that is +exposed is also shown. + +By default this is off for all contexts. +Instead of t, this can also be an alist specifying this option for different +contexts. See `org-show-hierarchy-above' for valid contexts." + :group 'org-reveal-location + :type org-context-choice) (defgroup org-cycle nil "Options concerning visibility cycling in Org-mode." :tag "Org Cycle" :group 'org-structure) -(defcustom org-cycle-global-at-bob t +(defcustom org-drawers '("PROPERTIES" "CLOCK") + "Names of drawers. Drawers are not opened by cycling on the headline above. +Drawers only open with a TAB on the drawer line itself. A drawer looks like +this: + :DRAWERNAME: + ..... + :END: +The drawer \"PROPERTIES\" is special for capturing properties through +the property API. + +Drawers can be defined on the per-file basis with a line like: + +#+DRAWERS: HIDDEN STATE PROPERTIES" + :group 'org-structure + :type '(repeat (string :tag "Drawer Name"))) + +(defcustom org-cycle-global-at-bob nil "Cycle globally if cursor is at beginning of buffer and not at a headline. This makes it possible to do global cycling without having to use S-TAB or C-u TAB. For this special case to work, the first line of the buffer @@ -384,8 +487,9 @@ of the buffer." "Where should `org-cycle' emulate TAB. nil Never white Only in completely white lines -whitestart Only at the beginning of lines, before the first non-white char. +whitestart Only at the beginning of lines, before the first non-white char t Everywhere except in headlines +exc-hl-bol Everywhere except at the start of a headline If TAB is used in a place where it does not emulate TAB, the current subtree visibility is cycled." :group 'org-cycle @@ -393,9 +497,26 @@ visibility is cycled." (const :tag "Only in completely white lines" white) (const :tag "Before first char in a line" whitestart) (const :tag "Everywhere except in headlines" t) + (const :tag "Everywhere except at bol in headlines" exc-hl-bol) )) +(defcustom org-cycle-separator-lines 2 + "Number of empty lines needed to keep an empty line between collapsed trees. +If you leave an empty line between the end of a subtree and the following +headline, this empty line is hidden when the subtree is folded. +Org-mode will leave (exactly) one empty line visible if the number of +empty lines is equal or larger to the number given in this variable. +So the default 2 means, at least 2 empty lines after the end of a subtree +are needed to produce free space between a collapsed subtree and the +following headline. + +Special case: when 0, never leave empty lines in collapsed view." + :group 'org-cycle + :type 'integer) + (defcustom org-cycle-hook '(org-cycle-hide-archived-subtrees + org-cycle-hide-drawers + org-cycle-show-empty-lines org-optimize-window-after-visibility-change) "Hook that is run after `org-cycle' has changed the buffer visibility. The function(s) in this hook must accept a single argument which indicates @@ -406,7 +527,6 @@ the values `folded', `children', or `subtree'." :group 'org-cycle :type 'hook) - (defgroup org-edit-structure nil "Options concerning structure editing in Org-mode." :tag "Org Edit Structure" @@ -437,6 +557,67 @@ body starts at column 0, indentation is not changed at all." :group 'org-edit-structure :type 'boolean) +(defcustom org-special-ctrl-a/e nil + "Non-nil means `C-a' and `C-e' behave specially in headlines and items. +When t, `C-a' will bring back the cursor to the beginning of the +headline text, i.e. after the stars and after a possible TODO keyword. +In an item, this will be the position after the bullet. +When the cursor is already at that position, another `C-a' will bring +it to the beginning of the line. +`C-e' will jump to the end of the headline, ignoring the presence of tags +in the headline. A second `C-e' will then jump to the true end of the +line, after any tags. +When set to the symbol `reversed', the first `C-a' or `C-e' works normally, +and only a directly following, identical keypress will bring the cursor +to the special positions." + :group 'org-edit-structure + :type '(choice + (const :tag "off" nil) + (const :tag "after bullet first" t) + (const :tag "border first" reversed))) + +(if (fboundp 'defvaralias) + (defvaralias 'org-special-ctrl-a 'org-special-ctrl-a/e)) + +(defcustom org-special-ctrl-k nil + "Non-nil means `C-k' will behave specially in headlines. +When nil, `C-k' will call the default `kill-line' command. +When t, the following will happen while the cursor is in the headline: + +- When the cursor is at the beginning of a headline, kill the entire + line and possible the folded subtree below the line. +- When in the middle of the headline text, kill the headline up to the tags. +- When after the headline text, kill the tags." + :group 'org-edit-structure + :type 'boolean) + +(defcustom org-M-RET-may-split-line '((default . t)) + "Non-nil means, M-RET will split the line at the cursor position. +When nil, it will go to the end of the line before making a +new line. +You may also set this option in a different way for different +contexts. Valid contexts are: + +headline when creating a new headline +item when creating a new item +table in a table field +default the value to be used for all contexts not explicitly + customized" + :group 'org-structure + :group 'org-table + :type '(choice + (const :tag "Always" t) + (const :tag "Never" nil) + (repeat :greedy t :tag "Individual contexts" + (cons + (choice :tag "Context" + (const headline) + (const item) + (const table) + (const default)) + (boolean))))) + + (defcustom org-blank-before-new-entry '((heading . nil) (plain-list-item . nil)) "Should `org-insert-heading' leave a blank line before new heading/item? @@ -450,7 +631,7 @@ and a boolean flag as cdr." (defcustom org-insert-heading-hook nil "Hook being run after inserting a new heading." :group 'org-edit-structure - :type 'boolean) + :type 'hook) (defcustom org-enable-fixed-width-editor t "Non-nil means, lines starting with \":\" are treated as fixed-width. @@ -460,6 +641,11 @@ See also the QUOTE keyword." :group 'org-edit-structure :type 'boolean) +(defcustom org-goto-auto-isearch t + "Non-nil means, typing characters in org-goto starts incremental search." + :group 'org-edit-structure + :type 'boolean) + (defgroup org-sparse-trees nil "Options concerning sparse trees in Org-mode." :tag "Org Sparse Trees" @@ -540,7 +726,9 @@ with \\[org-ctrl-c-ctrl-c\\]." (defcustom org-archive-tag "ARCHIVE" "The tag that marks a subtree as archived. An archived subtree does not open during visibility cycling, and does -not contribute to the agenda listings." +not contribute to the agenda listings. +After changing this, font-lock must be restarted in the relevant buffers to +get the proper fontification." :group 'org-archive :group 'org-keywords :type 'string) @@ -606,18 +794,63 @@ line like :type 'string) (defcustom org-archive-mark-done t - "Non-nil means, mark entries as DONE when they are moved to the archive file." + "Non-nil means, mark entries as DONE when they are moved to the archive file. +This can be a string to set the keyword to use. When t, Org-mode will +use the first keyword in its list that means done." :group 'org-archive - :type 'boolean) + :type '(choice + (const :tag "No" nil) + (const :tag "Yes" t) + (string :tag "Use this keyword"))) (defcustom org-archive-stamp-time t "Non-nil means, add a time stamp to entries moved to an archive file. -The time stamp will be added directly after the TODO state keyword in the -first line, so it is probably best to use this in combinations with -`org-archive-mark-done'." +This variable is obsolete and has no effect anymore, instead add ot remove +`time' from the variablle `org-archive-save-context-info'." :group 'org-archive :type 'boolean) +(defcustom org-archive-save-context-info '(time file olpath category todo itags) + "Parts of context info that should be stored as properties when archiving. +When a subtree is moved to an archive file, it looses information given by +context, like inherited tags, the category, and possibly also the TODO +state (depending on the variable `org-archive-mark-done'). +This variable can be a list of any of the following symbols: + +time The time of archiving. +file The file where the entry originates. +itags The local tags, in the headline of the subtree. +ltags The tags the subtree inherits from further up the hierarchy. +todo The pre-archive TODO state. +category The category, taken from file name or #+CATEGORY lines. +olpath The outline path to the item. These are all headlines above + the current item, separated by /, like a file path. + +For each symbol present in the list, a property will be created in +the archived entry, with a prefix \"PRE_ARCHIVE_\", to remember this +information." + :group 'org-archive + :type '(set :greedy t + (const :tag "Time" time) + (const :tag "File" file) + (const :tag "Category" category) + (const :tag "TODO state" todo) + (const :tag "TODO state" priority) + (const :tag "Inherited tags" itags) + (const :tag "Outline path" olpath) + (const :tag "Local tags" ltags))) + +(defgroup org-imenu-and-speedbar nil + "Options concerning imenu and speedbar in Org-mode." + :tag "Org Imenu and Speedbar" + :group 'org-structure) + +(defcustom org-imenu-depth 2 + "The maximum level for Imenu access to Org-mode headlines. +This also applied for speedbar access." + :group 'org-imenu-and-speedbar + :type 'number) + (defgroup org-table nil "Options concerning tables in Org-mode." :tag "Org Table" @@ -706,7 +939,7 @@ table, obtained by prompting the user." :type 'string) (defcustom org-table-number-regexp - "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%:]*\\|\\(0[xX]\\)[0-9a-fA-F]+\\)$" + "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%:]*\\|\\(0[xX]\\)[0-9a-fA-F]+\\|nan\\)$" "Regular expression for recognizing numbers in table columns. If a table column contains mostly numbers, it will be aligned to the right. If not, it will be aligned to the left. @@ -731,7 +964,7 @@ Other options offered by the customize interface are more restrictive." (const :tag "Exponential, Floating point, Integer" "^[-+]?[0-9.]+\\([eEdD][-+0-9]+\\)?$") (const :tag "Very General Number-Like, including hex" - "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%]*\\|\\(0[xX]\\)[0-9a-fA-F]+\\)$") + "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%]*\\|\\(0[xX]\\)[0-9a-fA-F]+\\|nan\\)$") (string :tag "Regexp:"))) (defcustom org-table-number-fraction 0.5 @@ -743,7 +976,7 @@ alignment to the right border applies." :type 'number) (defgroup org-table-editing nil - "Bahavior of tables during editing in Org-mode." + "Behavior of tables during editing in Org-mode." :tag "Org Table Editing" :group 'org-table) @@ -783,6 +1016,18 @@ calls `table-recognize-table'." :tag "Org Table Calculation" :group 'org-table) +(defcustom org-table-use-standard-references t + "Should org-mode work with table refrences like B3 instead of @3$2? +Possible values are: +nil never use them +from accept as input, do not present for editing +t: accept as input and present for editing" + :group 'org-table-calculation + :type '(choice + (const :tag "Never, don't even check unser input for them" nil) + (const :tag "Always, both as user input, and when editing" t) + (const :tag "Convert user input, don't offer during editing" 'from))) + (defcustom org-table-copy-increment t "Non-nil means, increment when copying current field with \\[org-table-copy-down]." :group 'org-table-calculation @@ -815,9 +1060,6 @@ the command \\[org-table-eval-formula]." :group 'org-table-calculation :type 'boolean) -;; FIXME this is also a variable that makes Org-mode files non-portable -;; Maybe I should have a #+ options for constants? -;; How about the SI/cgs issue? (defcustom org-table-formula-use-constants t "Non-nil means, interpret constants in formulas in tables. A constant looks like `$c' or `$Grav' and will be replaced before evaluation @@ -834,12 +1076,20 @@ speed of light in a formula, you would configure (setq org-table-formula-constants '((\"c\" . \"299792458.\"))) -and then use it in an equation like `$1*$c'." +and then use it in an equation like `$1*$c'. + +Constants can also be defined on a per-file basis using a line like + +#+CONSTANTS: c=299792458. pi=3.14 eps=2.4e-6" :group 'org-table-calculation :type '(repeat (cons (string :tag "name") (string :tag "value")))) +(defvar org-table-formula-constants-local nil + "Local version of `org-table-formula-constants'.") +(make-variable-buffer-local 'org-table-formula-constants-local) + (defcustom org-table-allow-automatic-line-recalculation t "Non-nil means, lines marked with |#| or |*| will be recomputed automatically. Automatically means, when TAB or RET or C-c C-c are pressed in the line." @@ -852,7 +1102,7 @@ Automatically means, when TAB or RET or C-c C-c are pressed in the line." :group 'org) (defvar org-link-abbrev-alist-local nil - "buffer-local version of `org-link-abbrev-alist', which see. + "Buffer-local version of `org-link-abbrev-alist', which see. The value of this is taken from the #+LINK lines.") (make-variable-buffer-local 'org-link-abbrev-alist-local) @@ -865,15 +1115,18 @@ links in Org-mode buffers can have an optional tag after a double colon, e.g. [[linkkey:tag][description]] If REPLACE is a string, the tag will simply be appended to create the link. -If the string contains \"%s\", the tag will be inserted there. REPLACE may -also be a function that will be called with the tag as the only argument to -create the link. See the manual for examples." +If the string contains \"%s\", the tag will be inserted there. + +REPLACE may also be a function that will be called with the tag as the +only argument to create the link, which should be returned as a string. + +See the manual for examples." :group 'org-link :type 'alist) (defcustom org-descriptive-links t "Non-nil means, hide link part and only show description of bracket links. -Bracket links are like [[link][descritpion]]. This variable sets the initial +Bracket links are like [[link][descritpion]]. This variable sets the initial state in new org-mode buffers. The setting can then be toggled on a per-buffer basis from the Org->Hyperlinks menu." :group 'org-link @@ -883,10 +1136,10 @@ per-buffer basis from the Org->Hyperlinks menu." "How the path name in file links should be stored. Valid values are: -relative relative to the current directory, i.e. the directory of the file +relative Relative to the current directory, i.e. the directory of the file into which the link is being inserted. -absolute absolute path, if possible with ~ for home directory. -noabbrev absolute path, no abbreviation of home directory. +absolute Absolute path, if possible with ~ for home directory. +noabbrev Absolute path, no abbreviation of home directory. adaptive Use relative path for files in the current directory and sub- directories of it. For other files, use an absolute path." :group 'org-link @@ -914,13 +1167,13 @@ Changing this variable requires a restart of Emacs to become effective." :group 'org-link :type '(set (const :tag "Double bracket links (new style)" bracket) (const :tag "Angular bracket links (old style)" angular) - (const :tag "plain text links" plain) + (const :tag "Plain text links" plain) (const :tag "Radio target matches" radio) (const :tag "Tags" tag) (const :tag "Timestamps" date))) (defgroup org-link-store nil - "Options concerning storing links in Org-mode" + "Options concerning storing links in Org-mode." :tag "Org Store Link" :group 'org-link) @@ -988,10 +1241,15 @@ negates this setting for the duration of the command." :type 'boolean) (defgroup org-link-follow nil - "Options concerning following links in Org-mode" + "Options concerning following links in Org-mode." :tag "Org Follow Link" :group 'org-link) +(defcustom org-follow-link-hook nil + "Hook that is run after a link has been followed." + :group 'org-link-follow + :type 'hook) + (defcustom org-tab-follows-link nil "Non-nil means, on links TAB will follow the link. Needs to be set before org.el is loaded." @@ -1004,9 +1262,10 @@ Needs to be set before org.el is loaded." :group 'org-link-follow :type 'boolean) -(defcustom org-mouse-1-follows-link t +(defcustom org-mouse-1-follows-link + (if (boundp 'mouse-1-click-follows-link) mouse-1-click-follows-link t) "Non-nil means, mouse-1 on a link will follow the link. -A longer mouse click will still set point. Does not wortk on XEmacs. +A longer mouse click will still set point. Does not work on XEmacs. Needs to be set before org.el is loaded." :group 'org-link-follow :type 'boolean) @@ -1087,15 +1346,15 @@ if one was given like in ." (defcustom org-confirm-shell-link-function 'yes-or-no-p "Non-nil means, ask for confirmation before executing shell links. -Shell links can be dangerous, just thing about a link +Shell links can be dangerous: just think about a link [[shell:rm -rf ~/*][Google Search]] -This link would show up in your Org-mode document as \"Google Search\" +This link would show up in your Org-mode document as \"Google Search\", but really it would remove your entire home directory. -Therefore I *definitely* advise against setting this variable to nil. -Just change it to `y-or-n-p' of you want to confirm with a single key press -rather than having to type \"yes\"." +Therefore we advise against setting this variable to nil. +Just change it to `y-or-n-p' of you want to confirm with a +single keystroke rather than having to type \"yes\"." :group 'org-link-follow :type '(choice (const :tag "with yes-or-no (safer)" yes-or-no-p) @@ -1103,16 +1362,16 @@ rather than having to type \"yes\"." (const :tag "no confirmation (dangerous)" nil))) (defcustom org-confirm-elisp-link-function 'yes-or-no-p - "Non-nil means, ask for confirmation before executing elisp links. -Elisp links can be dangerous, just think about a link + "Non-nil means, ask for confirmation before executing Emacs Lisp links. +Elisp links can be dangerous: just think about a link [[elisp:(shell-command \"rm -rf ~/*\")][Google Search]] -This link would show up in your Org-mode document as \"Google Search\" +This link would show up in your Org-mode document as \"Google Search\", but really it would remove your entire home directory. -Therefore I *definitely* advise against setting this variable to nil. -Just change it to `y-or-n-p' of you want to confirm with a single key press -rather than having to type \"yes\"." +Therefore we advise against setting this variable to nil. +Just change it to `y-or-n-p' of you want to confirm with a +single keystroke rather than having to type \"yes\"." :group 'org-link-follow :type '(choice (const :tag "with yes-or-no (safer)" yes-or-no-p) @@ -1228,6 +1487,46 @@ You can set this on a per-template basis with the variable (const :tag "Default from remember-data-file" nil) file)) +(defcustom org-remember-store-without-prompt t + "Non-nil means, `C-c C-c' stores remember note without further promts. +In this case, you need `C-u C-c C-c' to get the prompts for +note file and headline. +When this variable is nil, `C-c C-c' give you the prompts, and +`C-u C-c C-c' trigger the fasttrack." + :group 'org-remember + :type 'boolean) + +(defcustom org-remember-interactive-interface 'refile + "The interface to be used for interactive filing of remember notes. +This is only used when the interactive mode for selecting a filing +location is used (see the variable `org-remember-store-without-prompt'). +Allowed vaues are: +outline The interface shows an outline of the relevant file + and the correct heading is found by moving through + the outline or by searching with incremental search. +outline-path-completion Headlines in the current buffer are offered via + completion. +refile Use the refile interface, and offer headlines, + possibly from different buffers." + :group 'org-remember + :type '(choice + (const :tag "Refile" refile) + (const :tag "Outline" outline) + (const :tag "Outline-path-completion" outline-path-completion))) + +(defcustom org-goto-interface 'outline + "The default interface to be used for `org-goto'. +Allowed vaues are: +outline The interface shows an outline of the relevant file + and the correct heading is found by moving through + the outline or by searching with incremental search. +outline-path-completion Headlines in the current buffer are offered via + completion." + :group 'org-remember ; FIXME: different group for org-goto and org-refile + :type '(choice + (const :tag "Outline" outline) + (const :tag "Outline-path-completion" outline-path-completion))) + (defcustom org-remember-default-headline "" "The headline that should be the default location in the notes file. When filing remember notes, the cursor will start at that position. @@ -1239,20 +1538,29 @@ You can set this on a per-template basis with the variable (defcustom org-remember-templates nil "Templates for the creation of remember buffers. When nil, just let remember make the buffer. -When not nil, this is a list of 4-element lists. In each entry, the first -element is a character, a unique key to select this template. -The second element is the template. The third element is optional and can +When not nil, this is a list of 5-element lists. In each entry, the first +element is the name of the template, which should be a single short word. +The second element is a character, a unique key to select this template. +The third element is the template. The fourth element is optional and can specify a destination file for remember items created with this template. -The default file is given by `org-default-notes-file'. An optional third +The default file is given by `org-default-notes-file'. An optional fifth element can specify the headline in that file that should be offered first when the user is asked to file the entry. The default headline is given in the variable `org-remember-default-headline'. +An optional sixth element specifies the contexts in which the user can +select the template. This element can be either a list of major modes +or a function. `org-remember' will first check whether the function +returns `t' or if we are in any of the listed major modes, and select +the template accordingly. + The template specifies the structure of the remember buffer. It should have a first line starting with a star, to act as the org-mode headline. Furthermore, the following %-escapes will be replaced with content: - %^{prompt} prompt the user for a string and replace this sequence with it. + %^{prompt} Prompt the user for a string and replace this sequence with it. + A default value and a completion table ca be specified like this: + %^{prompt|default|completion2|completion3|...} %t time stamp, date only %T time stamp with date and time %u, %U like the above, but inactive time stamps @@ -1260,9 +1568,15 @@ Furthermore, the following %-escapes will be replaced with content: You may define a prompt like %^{Please specify birthday}t %n user name (taken from `user-full-name') %a annotation, normally the link created with org-store-link - %i initial content, the region when remember is called with C-u. - If %i is indented, the entire inserted text will be indented - as well. + %i initial content, the region active. If %i is indented, + the entire inserted text will be indented as well. + %c content of the clipboard, or current kill ring head + %^g prompt for tags, with completion on tags in target file + %^G prompt for tags, with completion all tags in all agenda files + %:keyword specific information for certain link types, see below + %[pathname] insert the contents of the file given by `pathname' + %(sexp) evaluate elisp `(sexp)' and replace with the result + %! Store this note immediately after filling the template %? After completing the template, position cursor here. @@ -1284,23 +1598,37 @@ w3, w3m | %:type %:url info | %:type %:file %:node calendar | %:type %:date" :group 'org-remember - :get (lambda (var) ; Make sure all entries have 4 elements + :get (lambda (var) ; Make sure all entries have at least 5 elements (mapcar (lambda (x) - (cond ((= (length x) 3) (append x '(""))) - ((= (length x) 2) (append x '("" ""))) + (if (not (stringp (car x))) (setq x (cons "" x))) + (cond ((= (length x) 4) (append x '(""))) + ((= (length x) 3) (append x '("" ""))) (t x))) (default-value var))) :type '(repeat :tag "enabled" - (list :value (?a "\n" nil nil) + (list :value ("" ?a "\n" nil nil nil) + (string :tag "Name") (character :tag "Selection Key") (string :tag "Template") - (file :tag "Destination file (optional)") - (string :tag "Destination headline (optional)")))) + (choice + (file :tag "Destination file") + (const :tag "Prompt for file" nil)) + (choice + (string :tag "Destination headline") + (const :tag "Selection interface for heading")) + (choice + (const :tag "Use by default" nil) + (const :tag "Use in all contexts" t) + (repeat :tag "Use only if in major mode" + (symbol :tag "Major mode")) + (function :tag "Perform a check against function"))))) (defcustom org-reverse-note-order nil "Non-nil means, store new notes at the beginning of a file or entry. -When nil, new notes will be filed to the end of a file or entry." +When nil, new notes will be filed to the end of a file or entry. +This can also be a list with cons cells of regular expressions that +are matched against file names, and values." :group 'org-remember :type '(choice (const :tag "Reverse always" t) @@ -1308,6 +1636,51 @@ When nil, new notes will be filed to the end of a file or entry." (repeat :tag "By file name regexp" (cons regexp boolean)))) +(defcustom org-refile-targets nil + "Targets for refiling entries with \\[org-refile]. +This is list of cons cells. Each cell contains: +- a specification of the files to be considered, either a list of files, + or a symbol whose function or value fields will be used to retrieve + a file name or a list of file names. Nil means, refile to a different + heading in the current buffer. +- A specification of how to find candidate refile targets. This may be + any of + - a cons cell (:tag . \"TAG\") to identify refile targets by a tag. + This tag has to be present in all target headlines, inheritance will + not be considered. + - a cons cell (:todo . \"KEYWORD\") to identify refile targets by + todo keyword. + - a cons cell (:regexp . \"REGEXP\") with a regular expression matching + headlines that are refiling targets. + - a cons cell (:level . N). Any headline of level N is considered a target. + - a cons cell (:maxlevel . N). Any headline with level <= N is a target." +;; FIXME: what if there are a var and func with same name??? + :group 'org-remember + :type '(repeat + (cons + (choice :value org-agenda-files + (const :tag "All agenda files" org-agenda-files) + (const :tag "Current buffer" nil) + (function) (variable) (file)) + (choice :tag "Identify target headline by" + (cons :tag "Specific tag" (const :tag) (string)) + (cons :tag "TODO keyword" (const :todo) (string)) + (cons :tag "Regular expression" (const :regexp) (regexp)) + (cons :tag "Level number" (const :level) (integer)) + (cons :tag "Max Level number" (const :maxlevel) (integer)))))) + +(defcustom org-refile-use-outline-path nil + "Non-nil means, provide refile targets as paths. +So a level 3 headline will be available as level1/level2/level3. +When the value is `file', also include the file name (without directory) +into the path. When `full-file-path', include the full file path." + :group 'org-remember + :type '(choice + (const :tag "Not" nil) + (const :tag "Yes" t) + (const :tag "Start with file name" file) + (const :tag "Start with full file path" full-file-path))) + (defgroup org-todo nil "Options concerning TODO items in Org-mode." :tag "Org TODO" @@ -1318,35 +1691,117 @@ When nil, new notes will be filed to the end of a file or entry." :tag "Org Progress" :group 'org-time) -(defcustom org-todo-keywords '("TODO" "DONE") - "List of TODO entry keywords. -\\By default, this is '(\"TODO\" \"DONE\"). The last entry in the list is -considered to mean that the entry is \"done\". All the other mean that -action is required, and will make the entry show up in todo lists, diaries -etc. -The command \\[org-todo] cycles an entry through these states, and an +(defcustom org-todo-keywords '((sequence "TODO" "DONE")) + "List of TODO entry keyword sequences and their interpretation. +\\This is a list of sequences. + +Each sequence starts with a symbol, either `sequence' or `type', +indicating if the keywords should be interpreted as a sequence of +action steps, or as different types of TODO items. The first +keywords are states requiring action - these states will select a headline +for inclusion into the global TODO list Org-mode produces. If one of +the \"keywords\" is the vertical bat \"|\" the remaining keywords +signify that no further action is necessary. If \"|\" is not found, +the last keyword is treated as the only DONE state of the sequence. + +The command \\[org-todo] cycles an entry through these states, and one additional state where no keyword is present. For details about this -cycling, see also the variable `org-todo-interpretation' -Changes become only effective after restarting Emacs." +cycling, see the manual. + +TODO keywords and interpretation can also be set on a per-file basis with +the special #+SEQ_TODO and #+TYP_TODO lines. + +Each keyword can optionally specify a character for fast state selection +\(in combination with the variable `org-use-fast-todo-selection') +and specifiers for state change logging, using the same syntax +that is used in the \"#+TODO:\" lines. For example, \"WAIT(w)\" says +that the WAIT state can be selected with the \"w\" key. \"WAIT(w!)\" +indicates to record a time stamp each time this state is selected. + +Each keyword may also specify if a timestamp or a note should be +recorded when entering or leaving the state, by adding additional +characters in the parenthesis after the keyword. This looks like this: +\"WAIT(w@/!)\". \"@\" means to add a note (with time), \"!\" means to +record only the time of the state change. With X and Y being either +\"@\" or \"!\", \"X/Y\" means use X when entering the state, and use +Y when leaving the state if and only if the *target* state does not +define X. You may omit any of the fast-selection key or X or /Y, +so WAIT(w@), WAIT(w/@) and WAIT(@/@) are all valid. + +For backward compatibility, this variable may also be just a list +of keywords - in this case the interptetation (sequence or type) will be +taken from the (otherwise obsolete) variable `org-todo-interpretation'." :group 'org-todo :group 'org-keywords - :type '(repeat (string :tag "Keyword"))) + :type '(choice + (repeat :tag "Old syntax, just keywords" + (string :tag "Keyword")) + (repeat :tag "New syntax" + (cons + (choice + :tag "Interpretation" + (const :tag "Sequence (cycling hits every state)" sequence) + (const :tag "Type (cycling directly to DONE)" type)) + (repeat + (string :tag "Keyword")))))) + +(defvar org-todo-keywords-1 nil + "All TODO and DONE keywords active in a buffer.") +(make-variable-buffer-local 'org-todo-keywords-1) +(defvar org-todo-keywords-for-agenda nil) +(defvar org-done-keywords-for-agenda nil) +(defvar org-not-done-keywords nil) +(make-variable-buffer-local 'org-not-done-keywords) +(defvar org-done-keywords nil) +(make-variable-buffer-local 'org-done-keywords) +(defvar org-todo-heads nil) +(make-variable-buffer-local 'org-todo-heads) +(defvar org-todo-sets nil) +(make-variable-buffer-local 'org-todo-sets) +(defvar org-todo-log-states nil) +(make-variable-buffer-local 'org-todo-log-states) +(defvar org-todo-kwd-alist nil) +(make-variable-buffer-local 'org-todo-kwd-alist) +(defvar org-todo-key-alist nil) +(make-variable-buffer-local 'org-todo-key-alist) +(defvar org-todo-key-trigger nil) +(make-variable-buffer-local 'org-todo-key-trigger) (defcustom org-todo-interpretation 'sequence "Controls how TODO keywords are interpreted. -This variable is only relevant if `org-todo-keywords' contains more than two -states. \\Possible values are `sequence' and `type'. - -When `sequence', \\[org-todo] will always switch to the next state in the -`org-todo-keywords' list. When `type', \\[org-todo] only cycles from state -to state when executed several times in direct succession. Otherwise, it -switches directly to DONE from any state. -See the manual for more information." +This variable is in principle obsolete and is only used for +backward compatibility, if the interpretation of todo keywords is +not given already in `org-todo-keywords'. See that variable for +more information." :group 'org-todo :group 'org-keywords :type '(choice (const sequence) (const type))) +(defcustom org-use-fast-todo-selection 'prefix + "Non-nil means, use the fast todo selection scheme with C-c C-t. +This variable describes if and under what circumstances the cycling +mechanism for TODO keywords will be replaced by a single-key, direct +selection scheme. + +When nil, fast selection is never used. + +When the symbol `prefix', it will be used when `org-todo' is called with +a prefix argument, i.e. `C-u C-c C-t' in an Org-mode buffer, and `C-u t' +in an agenda buffer. + +When t, fast selection is used by default. In this case, the prefix +argument forces cycling instead. + +In all cases, the special interface is only used if access keys have actually +been assigned by the user, i.e. if keywords in the configuration are followed +by a letter in parenthesis, like TODO(t)." + :group 'org-todo + :type '(choice + (const :tag "Never" nil) + (const :tag "By default" t) + (const :tag "Only with C-u C-c C-t" prefix))) + (defcustom org-after-todo-state-change-hook nil "Hook which is run after the state of a TODO item was changed. The new state (a string with a TODO keyword, or nil) is available in the @@ -1355,50 +1810,51 @@ Lisp variable `state'." :type 'hook) (defcustom org-log-done nil - "When set, insert a (non-active) time stamp when TODO entry is marked DONE. -When the state of an entry is changed from nothing to TODO, remove a previous -closing date. - -This can also be a list of symbols indicating under which conditions -the time stamp recording the action should be annotated with a short note. -Valid members of this list are - - done Offer to record a note when marking entries done - state Offer to record a note whenever changing the TODO state - of an item. This is only relevant if TODO keywords are - interpreted as sequence, see variable `org-todo-interpretation'. - When `state' is set, this includes tracking `done'. - clock-out Offer to record a note when clocking out of an item. - -A separate window will then pop up and allow you to type a note. -After finishing with C-c C-c, the note will be added directly after the -timestamp, as a plain list item. See also the variable -`org-log-note-headings'. - -Logging can also be configured on a per-file basis by adding one of + "Non-nil means, record a CLOSED timestamp when moving an entry to DONE. +When equal to the list (done), also prompt for a closing note. +This can also be configured on a per-file basis by adding one of the following lines anywhere in the buffer: #+STARTUP: logdone - #+STARTUP: nologging #+STARTUP: lognotedone - #+STARTUP: lognotestate - #+STARTUP: lognoteclock-out" + #+STARTUP: nologdone" :group 'org-todo :group 'org-progress :type '(choice - (const :tag "off" nil) - (const :tag "on" t) - (set :tag "on, with notes, detailed control" :greedy t :value (done) - (const :tag "when item is marked DONE" done) - (const :tag "when TODO state changes" state) - (const :tag "when clocking out" clock-out)))) + (const :tag "No logging" nil) + (const :tag "Record CLOSED timestamp" time) + (const :tag "Record CLOSED timestamp with closing note." note))) + +;; Normalize old uses of org-log-done. +(cond + ((eq org-log-done t) (setq org-log-done 'time)) + ((and (listp org-log-done) (memq 'done org-log-done)) + (setq org-log-done 'note))) + +;; FIXME: document +(defcustom org-log-note-clock-out nil + "Non-nil means, recored a note when clocking out of an item. +This can also be configured on a per-file basis by adding one of +the following lines anywhere in the buffer: + + #+STARTUP: lognoteclock-out + #+STARTUP: nolognoteclock-out" + :group 'org-todo + :group 'org-progress + :type 'boolean) + +(defcustom org-log-done-with-time t + "Non-nil means, the CLOSED time stamp will contain date and time. +When nil, only the date will be recorded." + :group 'org-progress + :type 'boolean) (defcustom org-log-note-headings '((done . "CLOSING NOTE %t") (state . "State %-12s %t") (clock-out . "")) "Headings for notes added when clocking out or closing TODO items. -The value is an alist, with the car being a sympol indicating the note +The value is an alist, with the car being a symbol indicating the note context, and the cdr is the heading to be used. The heading may also be the empty string. %t in the heading will be replaced by a time stamp. @@ -1414,30 +1870,99 @@ empty string. state) string) (cons (const :tag "Heading when clocking out" clock-out) string))) -(defcustom org-allow-auto-repeat t - "Non-nil means, find REPEAT cookies in entries and apply them. -A repeat cookie looks like REPEAT(+1m) and causes deadlines and schedules -to repeat themselves shifted by a certain amount of time, each time an -entry is marked DONE." +(defcustom org-log-states-order-reversed t + "Non-nil means, the latest state change note will be directly after heading. +When nil, the notes will be orderer according to time." :group 'org-todo :group 'org-progress :type 'boolean) +(defcustom org-log-repeat 'time + "Non-nil means, record moving through the DONE state when triggering repeat. +An auto-repeating tasks is immediately switched back to TODO when marked +done. If you are not logging state changes (by adding \"@\" or \"!\" to +the TODO keyword definition, or recording a cloing note by setting +`org-log-done', there will be no record of the task moving trhough DONE. +This variable forces taking a note anyway. Possible values are: + +nil Don't force a record +time Record a time stamp +note Record a note + +This option can also be set with on a per-file-basis with + + #+STARTUP: logrepeat + #+STARTUP: lognoterepeat + #+STARTUP: nologrepeat + +You can have local logging settings for a subtree by setting the LOGGING +property to one or more of these keywords." + :group 'org-todo + :group 'org-progress + :type '(choice + (const :tag "Don't force a record" nil) + (const :tag "Force recording the DONE state" time) + (const :tag "Force recording a note with the DONE state" note))) + +(defcustom org-clock-into-drawer 2 + "Should clocking info be wrapped into a drawer? +When t, clocking info will always be inserted into a :CLOCK: drawer. +If necessary, the drawer will be created. +When nil, the drawer will not be created, but used when present. +When an integer and the number of clocking entries in an item +reaches or exceeds this number, a drawer will be created." + :group 'org-todo + :group 'org-progress + :type '(choice + (const :tag "Always" t) + (const :tag "Only when drawer exists" nil) + (integer :tag "When at least N clock entries"))) + +(defcustom org-clock-out-when-done t + "When t, the clock will be stopped when the relevant entry is marked DONE. +Nil means, clock will keep running until stopped explicitly with +`C-c C-x C-o', or until the clock is started in a different item." + :group 'org-progress + :type 'boolean) + +(defcustom org-clock-in-switch-to-state nil + "Set task to a special todo state while clocking it. +The value should be the state to which the entry should be switched." + :group 'org-progress + :group 'org-todo + :type '(choice + (const :tag "Don't force a state" nil) + (string :tag "State"))) + (defgroup org-priorities nil "Priorities in Org-mode." :tag "Org Priorities" :group 'org-todo) +(defcustom org-highest-priority ?A + "The highest priority of TODO items. A character like ?A, ?B etc. +Must have a smaller ASCII number than `org-lowest-priority'." + :group 'org-priorities + :type 'character) + +(defcustom org-lowest-priority ?C + "The lowest priority of TODO items. A character like ?A, ?B etc. +Must have a larger ASCII number than `org-highest-priority'." + :group 'org-priorities + :type 'character) + (defcustom org-default-priority ?B "The default priority of TODO items. This is the priority an item get if no explicit priority is given." :group 'org-priorities :type 'character) -(defcustom org-lowest-priority ?C - "The lowest priority of TODO items. A character like ?A, ?B etc." +(defcustom org-priority-start-cycle-with-default t + "Non-nil means, start with default priority when starting to cycle. +When this is nil, the first step in the cycle will be (depending on the +command used) one higher or lower that the default priority." :group 'org-priorities - :type 'character) + :type 'boolean) (defgroup org-time nil "Options concerning time stamps and deadlines in Org-mode." @@ -1456,14 +1981,34 @@ the time stamp will always be forced into the second line." "Formats for `format-time-string' which are used for time stamps. It is not recommended to change this constant.") -(defcustom org-time-stamp-rounding-minutes 0 - "Number of minutes to round time stamps to upon insertion. -When zero, insert the time unmodified. Useful rounding numbers -should be factors of 60, so for example 5, 10, 15. -When this is not zero, you can still force an exact time-stamp by using -a double prefix argument to a time-stamp command like `C-c .' or `C-c !'." +(defcustom org-time-stamp-rounding-minutes '(0 5) + "Number of minutes to round time stamps to. +These are two values, the first applies when first creating a time stamp. +The second applies when changing it with the commands `S-up' and `S-down'. +When changing the time stamp, this means that it will change in steps +of N minutes, as given by the second value. + +When a setting is 0 or 1, insert the time unmodified. Useful rounding +numbers should be factors of 60, so for example 5, 10, 15. + +When this is larger than 1, you can still force an exact time-stamp by using +a double prefix argument to a time-stamp command like `C-c .' or `C-c !', +and by using a prefix arg to `S-up/down' to specify the exact number +of minutes to shift." :group 'org-time - :type 'integer) + :get '(lambda (var) ; Make sure all entries have 5 elements + (if (integerp (default-value var)) + (list (default-value var) 5) + (default-value var))) + :type '(list + (integer :tag "when inserting times") + (integer :tag "when modifying times"))) + +;; Make sure old customizations of this variable don't lead to problems. +(when (integerp org-time-stamp-rounding-minutes) + (setq org-time-stamp-rounding-minutes + (list org-time-stamp-rounding-minutes + org-time-stamp-rounding-minutes))) (defcustom org-display-custom-times nil "Non-nil means, overlay custom formats over all time stamps. @@ -1479,7 +2024,8 @@ To turn this on on a per-file basis, insert anywhere in the file: '("<%m/%d/%y %a>" . "<%m/%d/%y %a %H:%M>") ; american "Custom formats for time stamps. See `format-time-string' for the syntax. These are overlayed over the default ISO format if the variable -`org-display-custom-times' is set." +`org-display-custom-times' is set. Time like %H:%M should be at the +end of the second format." :group 'org-time :type 'sexp) @@ -1491,19 +2037,58 @@ These are overlayed over the default ISO format if the variable (concat "[" (substring f 1 -1) "]") f))) -(defcustom org-deadline-warning-days 30 - "No. of days before expiration during which a deadline becomes active. -This variable governs the display in sparse trees and in the agenda." - :group 'org-time - :type 'number) +(defcustom org-read-date-prefer-future t + "Non-nil means, assume future for incomplete date input from user. +This affects the following situations: +1. The user gives a day, but no month. + For example, if today is the 15th, and you enter \"3\", Org-mode will + read this as the third of *next* month. However, if you enter \"17\", + it will be considered as *this* month. +2. The user gives a month but not a year. + For example, if it is april and you enter \"feb 2\", this will be read + as feb 2, *next* year. \"May 5\", however, will be this year. -(defcustom org-popup-calendar-for-date-prompt t +When this option is nil, the current month and year will always be used +as defaults." + :group 'org-time + :type 'boolean) + +(defcustom org-read-date-display-live t + "Non-nil means, display current interpretation of date prompt live. +This display will be in an overlay, in the minibuffer." + :group 'org-time + :type 'boolean) + +(defcustom org-read-date-popup-calendar t "Non-nil means, pop up a calendar when prompting for a date. In the calendar, the date can be selected with mouse-1. However, the minibuffer will also be active, and you can simply enter the date as well. When nil, only the minibuffer will be available." :group 'org-time :type 'boolean) +(if (fboundp 'defvaralias) + (defvaralias 'org-popup-calendar-for-date-prompt + 'org-read-date-popup-calendar)) + +(defcustom org-extend-today-until 0 + "The hour when your day really ends. +This has influence for the following applications: +- When switching the agenda to \"today\". It it is still earlier than + the time given here, the day recognized as TODAY is actually yesterday. +- When a date is read from the user and it is still before the time given + here, the current date and time will be assumed to be yesterday, 23:59. + +FIXME: +IMPORTANT: This is still a very experimental feature, it may disappear +again or it may be extended to mean more things." + :group 'org-time + :type 'number) + +(defcustom org-edit-timestamp-down-means-later nil + "Non-nil means, S-down will increase the time in a time stamp. +When nil, S-up will increase." + :group 'org-time + :type 'boolean) (defcustom org-calendar-follow-timestamp-change t "Non-nil means, make the calendar window follow timestamp changes. @@ -1512,6 +2097,13 @@ moved to the new date." :group 'org-time :type 'boolean) +(defcustom org-clock-heading-function nil + "When non-nil, should be a function to create `org-clock-heading'. +This is the string shown in the mode line when a clock is running. +The function is called with point at the beginning of the headline." + :group 'org-time ; FIXME: Should we have a separate group???? + :type 'function) + (defgroup org-tags nil "Options concerning tags in Org-mode." :tag "Org Tags" @@ -1521,9 +2113,10 @@ moved to the new date." "List of tags allowed in Org-mode files. When this list is nil, Org-mode will base TAG input on what is already in the buffer. -The value of this variable is an alist, the car may be (and should) be a -character that is used to select that tag through the fast-tag-selection -interface. See the manual for details." +The value of this variable is an alist, the car of each entry must be a +keyword as a string, the cdr may be a character that is used to select +that tag through the fast-tag-selection interface. +See the manual for details." :group 'org-tags :type '(repeat (choice @@ -1559,11 +2152,15 @@ displaying the tags menu is not even shown, until you press C-c again." (const :tag "Yes" t) (const :tag "Expert" expert))) -(defcustom org-tags-column 48 +(defvar org-fast-tag-selection-include-todo nil + "Non-nil means, fast tags selection interface will also offer TODO states. +This is an undocumented feature, you should not rely on it.") + +(defcustom org-tags-column -80 "The column to which tags should be indented in a headline. If this number is positive, it specifies the column. If it is negative, it means that the tags should be flushright to that column. For example, --79 works well for a normal 80 character screen." +-80 works well for a normal 80 character screen." :group 'org-tags :type 'integer) @@ -1602,6 +2199,64 @@ make sure all corresponding TODO items find their way into the list." "History of minibuffer reads for tags.") (defvar org-last-tags-completion-table nil "The last used completion table for tags.") +(defvar org-after-tags-change-hook nil + "Hook that is run after the tags in a line have changed.") + +(defgroup org-properties nil + "Options concerning properties in Org-mode." + :tag "Org Properties" + :group 'org) + +(defcustom org-property-format "%-10s %s" + "How property key/value pairs should be formatted by `indent-line'. +When `indent-line' hits a property definition, it will format the line +according to this format, mainly to make sure that the values are +lined-up with respect to each other." + :group 'org-properties + :type 'string) + +(defcustom org-use-property-inheritance nil + "Non-nil means, properties apply also for sublevels. +This setting is only relevant during property searches, not when querying +an entry with `org-entry-get'. To retrieve a property with inheritance, +you need to call `org-entry-get' with the inheritance flag. +Turning this on can cause significant overhead when doing a search, so +this is turned off by default. +When nil, only the properties directly given in the current entry count. +The value may also be a list of properties that shouldhave inheritance. + +However, note that some special properties use inheritance under special +circumstances (not in searches). Examples are CATEGORY, ARCHIVE, COLUMNS, +and the properties ending in \"_ALL\" when they are used as descriptor +for valid values of a property." + :group 'org-properties + :type '(choice + (const :tag "Not" nil) + (const :tag "Always" nil) + (repeat :tag "Specific properties" (string :tag "Property")))) + +(defcustom org-columns-default-format "%25ITEM %TODO %3PRIORITY %TAGS" + "The default column format, if no other format has been defined. +This variable can be set on the per-file basis by inserting a line + +#+COLUMNS: %25ITEM ....." + :group 'org-properties + :type 'string) + +(defcustom org-global-properties nil + "List of property/value pairs that can be inherited by any entry. +You can set buffer-local values for this by adding lines like + +#+PROPERTY: NAME VALUE" + :group 'org-properties + :type '(repeat + (cons (string :tag "Property") + (string :tag "Value")))) + +(defvar org-local-properties nil + "List of property/value pairs that can be inherited by any entry. +Valid for the current buffer. +This variable is populated from #+PROPERTY lines.") (defgroup org-agenda nil "Options concerning agenda views in Org-mode." @@ -1612,7 +2267,7 @@ make sure all corresponding TODO items find their way into the list." "Variable used by org files to set a category for agenda display. Such files should use a file variable to set it, for example - -*- mode: org; org-category: \"ELisp\" +# -*- mode: org; org-category: \"ELisp\" or contain a special line @@ -1627,14 +2282,45 @@ is used instead.") Entries may be added to this list with \\[org-agenda-file-to-front] and removed with \\[org-remove-file]. You can also use customize to edit the list. +If an entry is a directory, all files in that directory that are matched by +`org-agenda-file-regexp' will be part of the file list. + If the value of the variable is not a list but a single file name, then the list of agenda files is actually stored and maintained in that file, one agenda file per line." :group 'org-agenda :type '(choice - (repeat :tag "List of files" file) + (repeat :tag "List of files and directories" file) (file :tag "Store list in a file\n" :value "~/.agenda_files"))) +(defcustom org-agenda-file-regexp "\\`[^.].*\\.org\\'" + "Regular expression to match files for `org-agenda-files'. +If any element in the list in that variable contains a directory instead +of a normal file, all files in that directory that are matched by this +regular expression will be included." + :group 'org-agenda + :type 'regexp) + +(defcustom org-agenda-skip-unavailable-files nil + "t means to just skip non-reachable files in `org-agenda-files'. +Nil means to remove them, after a query, from the list." + :group 'org-agenda + :type 'boolean) + +(defcustom org-agenda-text-search-extra-files nil + "List of extra files to be searched by text search commands. +These files will be search in addition to the agenda files bu the +commands `org-search-view' (`C-c a s') and `org-occur-in-agenda-files'. +Note that these files will only be searched for text search commands, +not for the other agenda views like todo lists, tag earches or the weekly +agenda. This variable is intended to list notes and possibly archive files +that should also be searched by these two commands." + :group 'org-agenda + :type '(repeat file)) + +(if (fboundp 'defvaralias) + (defvaralias 'org-agenda-multi-occur-extra-files + 'org-agenda-text-search-extra-files)) (defcustom org-agenda-confirm-kill 1 "When set, remote killing from the agenda buffer needs confirmation. @@ -1654,37 +2340,190 @@ forth between agenda and calendar." :group 'org-agenda :type 'sexp) +(defcustom org-agenda-compact-blocks nil + "Non-nil means, make the block agenda more compact. +This is done by leaving out unnecessary lines." + :group 'org-agenda + :type nil) + +(defgroup org-agenda-export nil + "Options concerning exporting agenda views in Org-mode." + :tag "Org Agenda Export" + :group 'org-agenda) + +(defcustom org-agenda-with-colors t + "Non-nil means, use colors in agenda views." + :group 'org-agenda-export + :type 'boolean) + +(defcustom org-agenda-exporter-settings nil + "Alist of variable/value pairs that should be active during agenda export. +This is a good place to set uptions for ps-print and for htmlize." + :group 'org-agenda-export + :type '(repeat + (list + (variable) + (sexp :tag "Value")))) + +(defcustom org-agenda-export-html-style "" + "The style specification for exported HTML Agenda files. +If this variable contains a string, it will replace the default + +or, if you want to keep the style in a file, + + + +As the value of this option simply gets inserted into the HTML header, +you can \"misuse\" it to also add other text to the header. However, + is required, if not present the variable will be ignored." + :group 'org-agenda-export + :group 'org-export-html + :type 'string) + (defgroup org-agenda-custom-commands nil "Options concerning agenda views in Org-mode." :tag "Org Agenda Custom Commands" :group 'org-agenda) -(defcustom org-agenda-custom-commands '(("w" todo "WAITING")) +(defconst org-sorting-choice + '(choice + (const time-up) (const time-down) + (const category-keep) (const category-up) (const category-down) + (const tag-down) (const tag-up) + (const priority-up) (const priority-down)) + "Sorting choices.") + +(defconst org-agenda-custom-commands-local-options + `(repeat :tag "Local settings for this command. Remember to quote values" + (choice :tag "Setting" + (list :tag "Any variable" + (variable :tag "Variable") + (sexp :tag "Value")) + (list :tag "Files to be searched" + (const org-agenda-files) + (list + (const :format "" quote) + (repeat + (file)))) + (list :tag "Sorting strategy" + (const org-agenda-sorting-strategy) + (list + (const :format "" quote) + (repeat + ,org-sorting-choice))) + (list :tag "Prefix format" + (const org-agenda-prefix-format :value " %-12:c%?-12t% s") + (string)) + (list :tag "Number of days in agenda" + (const org-agenda-ndays) + (integer :value 1)) + (list :tag "Fixed starting date" + (const org-agenda-start-day) + (string :value "2007-11-01")) + (list :tag "Start on day of week" + (const org-agenda-start-on-weekday) + (choice :value 1 + (const :tag "Today" nil) + (number :tag "Weekday No."))) + (list :tag "Include data from diary" + (const org-agenda-include-diary) + (boolean)) + (list :tag "Deadline Warning days" + (const org-deadline-warning-days) + (integer :value 1)) + (list :tag "Standard skipping condition" + :value (org-agenda-skip-function '(org-agenda-skip-entry-if)) + (const org-agenda-skip-function) + (list + (const :format "" quote) + (list + (choice + :tag "Skiping range" + (const :tag "Skip entry" org-agenda-skip-entry-if) + (const :tag "Skip subtree" org-agenda-skip-subtree-if)) + (repeat :inline t :tag "Conditions for skipping" + (choice + :tag "Condition type" + (list :tag "Regexp matches" :inline t (const :format "" 'regexp) (regexp)) + (list :tag "Regexp does not match" :inline t (const :format "" 'notregexp) (regexp)) + (const :tag "scheduled" 'scheduled) + (const :tag "not scheduled" 'notscheduled) + (const :tag "deadline" 'deadline) + (const :tag "no deadline" 'notdeadline)))))) + (list :tag "Non-standard skipping condition" + :value (org-agenda-skip-function) + (list + (const org-agenda-skip-function) + (sexp :tag "Function or form (quoted!)"))))) + "Selection of examples for agenda command settings. +This will be spliced into the custom type of +`org-agenda-custom-commands'.") + + +(defcustom org-agenda-custom-commands nil "Custom commands for the agenda. These commands will be offered on the splash screen displayed by the agenda dispatcher \\[org-agenda]. Each entry is a list like this: - (key type match options) + (key desc type match settings files) -key The key (a single char as a string) to be associated with the command. -type The command type, any of the following symbols: - todo Entries with a specific TODO keyword, in all agenda files. - tags Tags match in all agenda files. - tags-todo Tags match in all agenda files, TODO entries only. - todo-tree Sparse tree of specific TODO keyword in *current* file. - tags-tree Sparse tree with all tags matches in *current* file. - occur-tree Occur sparse tree for *current* file. -match What to search for: - - a single keyword for TODO keyword searches - - a tags match expression for tags searches - - a regular expression for occur searches -options A list of option setttings, similar to that in a let form, so like - this: ((opt1 val1) (opt2 val2) ...) +key The key (one or more characters as a string) to be associated + with the command. +desc A description of the command, when omitted or nil, a default + description is built using MATCH. +type The command type, any of the following symbols: + agenda The daily/weekly agenda. + todo Entries with a specific TODO keyword, in all agenda files. + search Entries containing search words entry or headline. + tags Tags/Property/TODO match in all agenda files. + tags-todo Tags/P/T match in all agenda files, TODO entries only. + todo-tree Sparse tree of specific TODO keyword in *current* file. + tags-tree Sparse tree with all tags matches in *current* file. + occur-tree Occur sparse tree for *current* file. + ... A user-defined function. +match What to search for: + - a single keyword for TODO keyword searches + - a tags match expression for tags searches + - a word search expression for text searches. + - a regular expression for occur searches + For all other commands, this should be the empty string. +settings A list of option settings, similar to that in a let form, so like + this: ((opt1 val1) (opt2 val2) ...). The values will be + evaluated at the moment of execution, so quote them when needed. +files A list of files file to write the produced agenda buffer to + with the command `org-store-agenda-views'. + If a file name ends in \".html\", an HTML version of the buffer + is written out. If it ends in \".ps\", a postscript version is + produced. Otherwide, only the plain text is written to the file. You can also define a set of commands, to create a composite agenda buffer. In this case, an entry looks like this: - (key desc (cmd1 cmd2 ...) general-options) + (key desc (cmd1 cmd2 ...) general-settings-for-whole-set files) where @@ -1692,84 +2531,116 @@ desc A description string to be displayed in the dispatcher menu. cmd An agenda command, similar to the above. However, tree commands are no allowed, but instead you can get agenda and global todo list. So valid commands for a set are: - (agenda) - (alltodo) - (stuck) - (todo \"match\" options) - (tags \"match\" options ) - (tags-todo \"match\" options) + (agenda \"\" settings) + (alltodo \"\" settings) + (stuck \"\" settings) + (todo \"match\" settings files) + (search \"match\" settings files) + (tags \"match\" settings files) + (tags-todo \"match\" settings files) Each command can carry a list of options, and another set of options can be given for the whole set of commands. Individual command options take -precedence over the general options." +precedence over the general options. + +When using several characters as key to a command, the first characters +are prefix commands. For the dispatcher to display useful information, you +should provide a description for the prefix, like + + (setq org-agenda-custom-commands + '((\"h\" . \"HOME + Name tag searches\") ; describe prefix \"h\" + (\"hl\" tags \"+HOME+Lisa\") + (\"hp\" tags \"+HOME+Peter\") + (\"hk\" tags \"+HOME+Kim\")))" :group 'org-agenda-custom-commands - :type '(repeat - (choice + :type `(repeat + (choice :value ("x" "Describe command here" tags "" nil) (list :tag "Single command" - (string :tag "Key") + (string :tag "Access Key(s) ") + (option (string :tag "Description")) (choice + (const :tag "Agenda" agenda) + (const :tag "TODO list" alltodo) + (const :tag "Search words" search) + (const :tag "Stuck projects" stuck) (const :tag "Tags search (all agenda files)" tags) (const :tag "Tags search of TODO entries (all agenda files)" tags-todo) (const :tag "TODO keyword search (all agenda files)" todo) (const :tag "Tags sparse tree (current buffer)" tags-tree) (const :tag "TODO keyword tree (current buffer)" todo-tree) (const :tag "Occur tree (current buffer)" occur-tree) - (symbol :tag "Other, user-defined function")) - (string :tag "Match") - (repeat :tag "Local options" - (list (variable :tag "Option") (sexp :tag "Value")))) + (sexp :tag "Other, user-defined function")) + (string :tag "Match (only for some commands)") + ,org-agenda-custom-commands-local-options + (option (repeat :tag "Export" (file :tag "Export to")))) (list :tag "Command series, all agenda files" - (string :tag "Key") - (string :tag "Description") - (repeat + (string :tag "Access Key(s)") + (string :tag "Description ") + (repeat :tag "Component" (choice - (const :tag "Agenda" (agenda)) - (const :tag "TODO list" (alltodo)) - (const :tag "Stuck projects" (stuck)) + (list :tag "Agenda" + (const :format "" agenda) + (const :tag "" :format "" "") + ,org-agenda-custom-commands-local-options) + (list :tag "TODO list (all keywords)" + (const :format "" alltodo) + (const :tag "" :format "" "") + ,org-agenda-custom-commands-local-options) + (list :tag "Search words" + (const :format "" search) + (string :tag "Match") + ,org-agenda-custom-commands-local-options) + (list :tag "Stuck projects" + (const :format "" stuck) + (const :tag "" :format "" "") + ,org-agenda-custom-commands-local-options) (list :tag "Tags search" (const :format "" tags) (string :tag "Match") - (repeat :tag "Local options" - (list (variable :tag "Option") - (sexp :tag "Value")))) - + ,org-agenda-custom-commands-local-options) (list :tag "Tags search, TODO entries only" (const :format "" tags-todo) (string :tag "Match") - (repeat :tag "Local options" - (list (variable :tag "Option") - (sexp :tag "Value")))) - + ,org-agenda-custom-commands-local-options) (list :tag "TODO keyword search" (const :format "" todo) (string :tag "Match") - (repeat :tag "Local options" - (list (variable :tag "Option") - (sexp :tag "Value")))) - + ,org-agenda-custom-commands-local-options) (list :tag "Other, user-defined function" (symbol :tag "function") (string :tag "Match") - (repeat :tag "Local options" - (list (variable :tag "Option") - (sexp :tag "Value")))))) + ,org-agenda-custom-commands-local-options))) - (repeat :tag "General options" - (list (variable :tag "Option") - (sexp :tag "Value"))))))) + (repeat :tag "Settings for entire command set" + (list (variable :tag "Any variable") + (sexp :tag "Value"))) + (option (repeat :tag "Export" (file :tag "Export to")))) + (cons :tag "Prefix key documentation" + (string :tag "Access Key(s)") + (string :tag "Description "))))) + +(defcustom org-agenda-query-register ?o + "The register holding the current query string. +The prupose of this is that if you construct a query string interactively, +you can then use it to define a custom command." + :group 'org-agenda-custom-commands + :type 'character) (defcustom org-stuck-projects - '("+LEVEL=2/-DONE" ("TODO" "NEXT" "NEXTACTION") nil) + '("+LEVEL=2/-DONE" ("TODO" "NEXT" "NEXTACTION") nil "") "How to identify stuck projects. -This is a list of three items: +This is a list of four items: 1. A tags/todo matcher string that is used to identify a project. - The entire tree below a headline matched by this is considered a project. -2. A list of TODO keywords itentifying non-stuck projects. + The entire tree below a headline matched by this is considered one project. +2. A list of TODO keywords identifying non-stuck projects. If the project subtree contains any headline with one of these todo - keywords, the project is consitered to be not stuck. + keywords, the project is considered to be not stuck. If you specify + \"*\" as a keyword, any TODO keyword will mark the project unstuck. 3. A list of tags identifying non-stuck projects. If the project subtree contains any headline with one of these tags, - the project is consitered to be not stuck. + the project is considered to be not stuck. If you specify \"*\" as + a tag, any tag will mark the project unstuck. +4. An arbitrary regular expression matching non-stuck projects. After defining this variable, you may use \\[org-agenda-list-stuck-projects] or `C-c a #' to produce the list." @@ -1777,7 +2648,8 @@ or `C-c a #' to produce the list." :type '(list (string :tag "Tags/TODO match to identify a project") (repeat :tag "Projects are *not* stuck if they have an entry with TODO keyword any of" (string)) - (repeat :tag "Projects are *not* stuck if they have an entry with TAG being any of" (string)))) + (repeat :tag "Projects are *not* stuck if they have an entry with TAG being any of" (string)) + (regexp :tag "Projects are *not* stuck if this regexp matches\ninside the subtree"))) (defgroup org-agenda-skip nil @@ -1793,10 +2665,22 @@ potentially much shorter TODO lists." :group 'org-todo :type 'boolean) +(defcustom org-agenda-todo-ignore-with-date nil + "Non-nil means, don't show entries with a date in the global todo list. +You can use this if you prefer to mark mere appointments with a TODO keyword, +but don't want them to show up in the TODO list. +When this is set, it also covers deadlines and scheduled items, the settings +of `org-agenda-todo-ignore-scheduled' and `org-agenda-todo-ignore-deadlines' +will be ignored." + :group 'org-agenda-skip + :group 'org-todo + :type 'boolean) + (defcustom org-agenda-todo-ignore-scheduled nil "Non-nil means, don't show scheduled entries in the global todo list. The idea behind this is that by scheduling it, you have already taken care -of this item." +of this item. +See also `org-agenda-todo-ignore-with-date'." :group 'org-agenda-skip :group 'org-todo :type 'boolean) @@ -1804,14 +2688,32 @@ of this item." (defcustom org-agenda-todo-ignore-deadlines nil "Non-nil means, don't show near deadline entries in the global todo list. Near means closer than `org-deadline-warning-days' days. -The idea behind this is that such items will appear in the agenda anyway." +The idea behind this is that such items will appear in the agenda anyway. +See also `org-agenda-todo-ignore-with-date'." :group 'org-agenda-skip :group 'org-todo :type 'boolean) (defcustom org-agenda-skip-scheduled-if-done nil "Non-nil means don't show scheduled items in agenda when they are done. -This is relevant for the daily/weekly agenda, not for the TODO list." +This is relevant for the daily/weekly agenda, not for the TODO list. And +it applies only to the actual date of the scheduling. Warnings about +an item with a past scheduling dates are always turned off when the item +is DONE." + :group 'org-agenda-skip + :type 'boolean) + +(defcustom org-agenda-skip-deadline-if-done nil + "Non-nil means don't show deadines when the corresponding item is done. +When nil, the deadline is still shown and should give you a happy feeling. +This is relevant for the daily/weekly agenda. And it applied only to the +actualy date of the deadline. Warnings about approching and past-due +deadlines are always turned off when the item is DONE." + :group 'org-agenda-skip + :type 'boolean) + +(defcustom org-agenda-skip-timestamp-if-done nil + "Non-nil means don't select item by timestamp or -range if it is DONE." :group 'org-agenda-skip :type 'boolean) @@ -1840,13 +2742,13 @@ N days, just insert a special line indicating the size of the gap." (defcustom org-agenda-mouse-1-follows-link nil "Non-nil means, mouse-1 on a link will follow the link in the agenda. -A longer mouse click will still set point. Does not wortk on XEmacs. +A longer mouse click will still set point. Does not work on XEmacs. Needs to be set before org.el is loaded." :group 'org-agenda-startup :type 'boolean) (defcustom org-agenda-start-with-follow-mode nil - "The initial value of follwo-mode in a newly created agenda window." + "The initial value of follow-mode in a newly created agenda window." :group 'org-agenda-startup :type 'boolean) @@ -1872,6 +2774,13 @@ See also the variable `org-agenda-restore-windows-after-quit'." (const other-window) (const reorganize-frame))) +(defcustom org-agenda-window-frame-fractions '(0.5 . 0.75) + "The min and max height of the agenda window as a fraction of frame height. +The value of the variable is a cons cell with two numbers between 0 and 1. +It only matters if `org-agenda-window-setup' is `reorganize-frame'." + :group 'org-agenda-windows + :type '(cons (number :tag "Minimum") (number :tag "Maximum"))) + (defcustom org-agenda-restore-windows-after-quit nil "Non-nil means, restore window configuration open exiting agenda. Before the window configuration is changed for displaying the agenda, @@ -1890,7 +2799,9 @@ Valid values are: current-window Display in the current window other-window Just display in another window. dedicated-frame Create one new frame, and re-use it each time. -new-frame Make a new frame each time." +new-frame Make a new frame each time. Note that in this case + previously-made indirect buffers are kept, and you need to + kill these buffers yourself." :group 'org-structure :group 'org-agenda-windows :type '(choice @@ -1924,13 +2835,25 @@ When nil, only the days which actually have entries are shown." :group 'org-agenda-daily/weekly :type 'boolean) -(defcustom org-agenda-date-format "%A %d %B %Y" +(defcustom org-agenda-format-date 'org-agenda-format-date-aligned "Format string for displaying dates in the agenda. Used by the daily/weekly agenda and by the timeline. This should be -a format string understood by `format-time-string'. -FIXME: Not used currently, because of timezone problem." +a format string understood by `format-time-string', or a function returning +the formatted date as a string. The function must take a single argument, +a calendar-style date list like (month day year)." :group 'org-agenda-daily/weekly - :type 'string) + :type '(choice + (string :tag "Format string") + (function :tag "Function"))) + +(defun org-agenda-format-date-aligned (date) + "Format a date string for display in the daily/weekly agenda, or timeline. +This function makes sure that dates are aligned for easy reading." + (format "%-9s %2d %s %4d" + (calendar-day-name date) + (cadr date) ; day + (calendar-month-name (car date)) ; month + (nth 2 date))) ; year (defcustom org-agenda-include-diary nil "If non-nil, include in the agenda entries from the Emacs Calendar's diary." @@ -1944,6 +2867,30 @@ the entries for specific days." :group 'org-agenda-daily/weekly :type 'boolean) +(defcustom org-agenda-repeating-timestamp-show-all t + "Non-nil means, show all occurences of a repeating stamp in the agenda. +When nil, only one occurence is shown, either today or the +nearest into the future." + :group 'org-agenda-daily/weekly + :type 'boolean) + +(defcustom org-deadline-warning-days 14 + "No. of days before expiration during which a deadline becomes active. +This variable governs the display in sparse trees and in the agenda. +When 0 or negative, it means use this number (the absolute value of it) +even if a deadline has a different individual lead time specified." + :group 'org-time + :group 'org-agenda-daily/weekly + :type 'number) + +(defcustom org-scheduled-past-days 10000 + "No. of days to continue listing scheduled items that are not marked DONE. +When an item is scheduled on a date, it shows up in the agenda on this +day and will be listed until it is marked done for the number of days +given here." + :group 'org-agenda-daily/weekly + :type 'number) + (defgroup org-agenda-time-grid nil "Options concerning the time grid in the Org-mode Agenda." :tag "Org Agenda Time Grid" @@ -1996,18 +2943,12 @@ a grid line." :tag "Org Agenda Sorting" :group 'org-agenda) -(let ((sorting-choice - '(choice - (const time-up) (const time-down) - (const category-keep) (const category-up) (const category-down) - (const tag-down) (const tag-up) - (const priority-up) (const priority-down)))) - - (defcustom org-agenda-sorting-strategy - '((agenda time-up category-keep priority-down) - (todo category-keep priority-down) - (tags category-keep)) - "Sorting structure for the agenda items of a single day. +(defcustom org-agenda-sorting-strategy + '((agenda time-up category-keep priority-down) + (todo category-keep priority-down) + (tags category-keep priority-down) + (search category-keep)) + "Sorting structure for the agenda items of a single day. This is a list of symbols which will be used in sequence to determine if an entry should be listed before another entry. The following symbols are recognized: @@ -2034,17 +2975,21 @@ the sequence given in `org-agenda-files'. Within each category sort by priority. Leaving out `category-keep' would mean that items will be sorted across -categories by priority." +categories by priority. + +Instead of a single list, this can also be a set of list for specific +contents, with a context symbol in the car of the list, any of +`agenda', `todo', `tags' for the corresponding agenda views." :group 'org-agenda-sorting :type `(choice - (repeat :tag "General" ,sorting-choice) + (repeat :tag "General" ,org-sorting-choice) (list :tag "Individually" (cons (const :tag "Strategy for Weekly/Daily agenda" agenda) - (repeat ,sorting-choice)) + (repeat ,org-sorting-choice)) (cons (const :tag "Strategy for TODO lists" todo) - (repeat ,sorting-choice)) + (repeat ,org-sorting-choice)) (cons (const :tag "Strategy for Tags matches" tags) - (repeat ,sorting-choice)))))) + (repeat ,org-sorting-choice))))) (defcustom org-sort-agenda-notime-is-late t "Non-nil means, items without time are considered late. @@ -2056,16 +3001,17 @@ agenda entries." :group 'org-agenda-sorting :type 'boolean) -(defgroup org-agenda-prefix nil +(defgroup org-agenda-line-format nil "Options concerning the entry prefix in the Org-mode agenda display." - :tag "Org Agenda Prefix" + :tag "Org Agenda Line Format" :group 'org-agenda) (defcustom org-agenda-prefix-format '((agenda . " %-12:c%?-12t% s") (timeline . " % s") (todo . " %-12:c") - (tags . " %-12:c")) + (tags . " %-12:c") + (search . " %-12:c")) "Format specifications for the prefix of items in the agenda views. An alist with four entries, for the different agenda types. The keys to the sublists are `agenda', `timeline', `todo', and `tags'. The values @@ -2113,20 +3059,50 @@ the prefix, you could use: (setq org-agenda-prefix-format \" %-11:c% s\") See also the variables `org-agenda-remove-times-when-in-prefix' and -`org-agenda-remove-tags-when-in-prefix'." +`org-agenda-remove-tags'." :type '(choice (string :tag "General format") (list :greedy t :tag "View dependent" (cons (const agenda) (string :tag "Format")) (cons (const timeline) (string :tag "Format")) (cons (const todo) (string :tag "Format")) - (cons (const tags) (string :tag "Format")))) - :group 'org-agenda-prefix) + (cons (const tags) (string :tag "Format")) + (cons (const search) (string :tag "Format")))) + :group 'org-agenda-line-format) (defvar org-prefix-format-compiled nil "The compiled version of the most recently used prefix format. See the variable `org-agenda-prefix-format'.") +(defcustom org-agenda-todo-keyword-format "%-1s" + "Format for the TODO keyword in agenda lines. +Set this to something like \"%-12s\" if you want all TODO keywords +to occupy a fixed space in the agenda display." + :group 'org-agenda-line-format + :type 'string) + +(defcustom org-agenda-scheduled-leaders '("Scheduled: " "Sched.%2dx: ") + "Text preceeding scheduled items in the agenda view. +This is a list with two strings. The first applies when the item is +scheduled on the current day. The second applies when it has been scheduled +previously, it may contain a %d to capture how many days ago the item was +scheduled." + :group 'org-agenda-line-format + :type '(list + (string :tag "Scheduled today ") + (string :tag "Scheduled previously"))) + +(defcustom org-agenda-deadline-leaders '("Deadline: " "In %3d d.: ") + "Text preceeding deadline items in the agenda view. +This is a list with two strings. The first applies when the item has its +deadline on the current day. The second applies when it is in the past or +in the future, it may contain %d to capture how many days away the deadline +is (was)." + :group 'org-agenda-line-format + :type '(list + (string :tag "Deadline today ") + (string :tag "Deadline relative"))) + (defcustom org-agenda-remove-times-when-in-prefix t "Non-nil means, remove duplicate time specifications in agenda items. When the format `org-agenda-prefix-format' contains a `%t' specifier, a @@ -2138,40 +3114,79 @@ cluttered. The option can be t or nil. It may also be the symbol `beg', indicating that the time should only be removed what it is located at the beginning of the headline/diary entry." - :group 'org-agenda-prefix + :group 'org-agenda-line-format :type '(choice (const :tag "Always" t) (const :tag "Never" nil) (const :tag "When at beginning of entry" beg))) -(defcustom org-agenda-remove-tags-when-in-prefix nil + +(defcustom org-agenda-default-appointment-duration nil + "Default duration for appointments that only have a starting time. +When nil, no duration is specified in such cases. +When non-nil, this must be the number of minutes, e.g. 60 for one hour." + :group 'org-agenda-line-format + :type '(choice + (integer :tag "Minutes") + (const :tag "No default duration"))) + + +(defcustom org-agenda-remove-tags nil "Non-nil means, remove the tags from the headline copy in the agenda. When this is the symbol `prefix', only remove tags when `org-agenda-prefix-format' contains a `%T' specifier." - :group 'org-agenda-prefix + :group 'org-agenda-line-format :type '(choice (const :tag "Always" t) (const :tag "Never" nil) (const :tag "When prefix format contains %T" prefix))) -(defcustom org-agenda-align-tags-to-column 65 - "Shift tags in agenda items to this column." - :group 'org-agenda-prefix +(if (fboundp 'defvaralias) + (defvaralias 'org-agenda-remove-tags-when-in-prefix + 'org-agenda-remove-tags)) + +(defcustom org-agenda-tags-column -80 + "Shift tags in agenda items to this column. +If this number is positive, it specifies the column. If it is negative, +it means that the tags should be flushright to that column. For example, +-80 works well for a normal 80 character screen." + :group 'org-agenda-line-format :type 'integer) +(if (fboundp 'defvaralias) + (defvaralias 'org-agenda-align-tags-to-column 'org-agenda-tags-column)) + +(defcustom org-agenda-fontify-priorities t + "Non-nil means, highlight low and high priorities in agenda. +When t, the highest priority entries are bold, lowest priority italic. +This may also be an association list of priority faces. The face may be +a names face, or a list like `(:background \"Red\")'." + :group 'org-agenda-line-format + :type '(choice + (const :tag "Never" nil) + (const :tag "Defaults" t) + (repeat :tag "Specify" + (list (character :tag "Priority" :value ?A) + (sexp :tag "face"))))) + (defgroup org-latex nil - "Options for embedding LaTeX code into Org-mode" + "Options for embedding LaTeX code into Org-mode." :tag "Org LaTeX" :group 'org) (defcustom org-format-latex-options - '(:foreground "Black" :background "Transparent" :scale 1.0 - :matchers ("begin" "$" "$$" "\\(" "\\[")) + '(:foreground default :background default :scale 1.0 + :html-foreground "Black" :html-background "Transparent" :html-scale 1.0 + :matchers ("begin" "$" "$$" "\\(" "\\[")) "Options for creating images from LaTeX fragments. This is a property list with the following properties: -:foreground the foreground color, for example \"Black\". +:foreground the foreground color for images embedded in emacs, e.g. \"Black\". + `default' means use the forground of the default face. :background the background color, or \"Transparent\". + `default' means use the background of the default face. :scale a scaling factor for the size of the images +:html-foreground, :html-background, :html-scale + The same numbers for HTML export. :matchers a list indicating which matchers should be used to find LaTeX fragments. Valid members of this list are: \"begin\" find environments @@ -2182,6 +3197,18 @@ This is a property list with the following properties: :group 'org-latex :type 'plist) +(defcustom org-format-latex-header "\\documentclass{article} +\\usepackage{fullpage} % do not remove +\\usepackage{amssymb} +\\usepackage[usenames]{color} +\\usepackage{amsmath} +\\usepackage{latexsym} +\\usepackage[mathscr]{eucal} +\\pagestyle{empty} % do not remove" + "The document header used for processing LaTeX fragments." + :group 'org-latex + :type 'string) + (defgroup org-export nil "Options for exporting org-listings." :tag "Org Export" @@ -2192,30 +3219,31 @@ This is a property list with the following properties: :tag "Org Export General" :group 'org-export) -(defcustom org-export-publishing-directory "." - "Path to the location where exported files should be located. -This path may be relative to the directory where the Org-mode file lives. -The default is to put them into the same directory as the Org-mode file. -The variable may also be an alist with export types `:html', `:ascii', -`:ical', or `:xoxo' and the corresponding directories. If a direcoty path -is relative, it is interpreted relative to the directory where the exported -Org-mode files lives." - :group 'org-export-general - :type '(choice - (directory) - (repeat - (cons - (choice :tag "Type" - (const :html) (const :ascii) (const :ical) (const :xoxo)) - (directory))))) +;; FIXME +(defvar org-export-publishing-directory nil) + +(defcustom org-export-with-special-strings t + "Non-nil means, interpret \"\-\", \"--\" and \"---\" for export. +When this option is turned on, these strings will be exported as: + + Org HTML LaTeX + -----+----------+-------- + \\- ­ \\- + -- – -- + --- — --- + ... … \ldots + +This option can also be set with the +OPTIONS line, e.g. \"-:nil\"." + :group 'org-export-translation + :type 'boolean) (defcustom org-export-language-setup '(("en" "Author" "Date" "Table of Contents") ("cs" "Autor" "Datum" "Obsah") ("da" "Ophavsmand" "Dato" "Indhold") ("de" "Autor" "Datum" "Inhaltsverzeichnis") - ("es" "Autor" "Fecha" "\xccndice") - ("fr" "Auteur" "Date" "Table des Mati\xe8res") + ("es" "Autor" "Fecha" "\xcdndice") + ("fr" "Auteur" "Date" "Table des mati\xe8res") ("it" "Autore" "Data" "Indice") ("nl" "Auteur" "Datum" "Inhoudsopgave") ("nn" "Forfattar" "Dato" "Innhold") ;; nn = Norsk (nynorsk) @@ -2237,6 +3265,12 @@ This should have an association in `org-export-language-setup'." :group 'org-export-general :type 'string) +(defcustom org-export-skip-text-before-1st-heading t + "Non-nil means, skip all text before the first headline when exporting. +When nil, that text is exported as well." + :group 'org-export-general + :type 'boolean) + (defcustom org-export-headline-levels 3 "The last level which is still exported as a headline. Inferior levels will produce itemize lists when exported. @@ -2303,6 +3337,23 @@ headline Only export the headline, but skip the tree below it." (const :tag "headline only" 'headline) (const :tag "entirely" t))) +(defcustom org-export-author-info t + "Non-nil means, insert author name and email into the exported file. + +This option can also be set with the +OPTIONS line, +e.g. \"author-info:nil\"." + :group 'org-export-general + :type 'boolean) + +(defcustom org-export-time-stamp-file t + "Non-nil means, insert a time stamp into the exported file. +The time stamp shows when the file was created. + +This option can also be set with the +OPTIONS line, +e.g. \"timestamp:nil\"." + :group 'org-export-general + :type 'boolean) + (defcustom org-export-with-timestamps t "If nil, do not export time stamps and associated keywords." :group 'org-export-general @@ -2316,13 +3367,26 @@ headline Only export the headline, but skip the tree below it." (defcustom org-export-with-tags 'not-in-toc "If nil, do not export tags, just remove them from headlines. If this is the symbol `not-in-toc', tags will be removed from table of -contents entries, but still be shown in the headlines of the document." +contents entries, but still be shown in the headlines of the document. + +This option can also be set with the +OPTIONS line, e.g. \"tags:nil\"." :group 'org-export-general :type '(choice (const :tag "Off" nil) (const :tag "Not in TOC" not-in-toc) (const :tag "On" t))) +(defcustom org-export-with-drawers nil + "Non-nil means, export with drawers like the property drawer. +When t, all drawers are exported. This may also be a list of +drawer names to export." + :group 'org-export-general + :type '(choice + (const :tag "All drawers" t) + (const :tag "None" nil) + (repeat :tag "Selected drawers" + (string :tag "Drawer name")))) + (defgroup org-export-translation nil "Options for translating special ascii sequences for the export backends." :tag "Org Export Translation" @@ -2339,6 +3403,14 @@ This option can also be set with the +OPTIONS line, e.g. \"*:nil\"." :group 'org-export-translation :type 'boolean) +(defcustom org-export-with-footnotes t + "If nil, export [1] as a footnote marker. +Lines starting with [1] will be formatted as footnotes. + +This option can also be set with the +OPTIONS line, e.g. \"f:nil\"." + :group 'org-export-translation + :type 'boolean) + (defcustom org-export-with-sub-superscripts t "Non-nil means, interpret \"_\" and \"^\" for export. When this option is turned on, you can use TeX-like syntax for sub- and @@ -2354,10 +3426,31 @@ sub- or superscripts. x_{i^2} or x^(2-i) braces or parenthesis do grouping. Still, ambiguity is possible - so when in doubt use {} to enclose the -sub/superscript. +sub/superscript. If you set this variable to the symbol `{}', +the braces are *required* in order to trigger interpretations as +sub/superscript. This can be helpful in documents that need \"_\" +frequently in plain text. + Not all export backends support this, but HTML does. This option can also be set with the +OPTIONS line, e.g. \"^:nil\"." + :group 'org-export-translation + :type '(choice + (const :tag "Always interpret" t) + (const :tag "Only with braces" {}) + (const :tag "Never interpret" nil))) + +(defcustom org-export-with-special-strings t + "Non-nil means, interpret \"\-\", \"--\" and \"---\" for export. +When this option is turned on, these strings will be exported as: + +\\- : ­ +-- : – +--- : — + +Not all export backends support this, but HTML does. + +This option can also be set with the +OPTIONS line, e.g. \"-:nil\"." :group 'org-export-translation :type 'boolean) @@ -2371,7 +3464,7 @@ Not all export backends support this. This option can also be set with the +OPTIONS line, e.g. \"TeX:nil\"." :group 'org-export-translation - :group 'org-latex + :group 'org-export-latex :type 'boolean) (defcustom org-export-with-LaTeX-fragments nil @@ -2383,7 +3476,7 @@ display math. This option can also be set with the +OPTIONS line, e.g. \"LaTeX:t\"." :group 'org-export-translation - :group 'org-latex + :group 'org-export-latex :type 'boolean) (defcustom org-export-with-fixed-width t @@ -2485,6 +3578,16 @@ Org-mode file." :tag "Org Export HTML" :group 'org-export) +(defcustom org-export-html-coding-system nil + "" + :group 'org-export-html + :type 'coding-system) + +(defcustom org-export-html-extension "html" + "The extension for exported HTML files." + :group 'org-export-html + :type 'string) + (defcustom org-export-html-style "")) + (insert org-agenda-export-html-style)) + (write-file file) + (kill-buffer (current-buffer)) + (message "HTML written to %s" file)) + ((string-match "\\.ps\\'" file) + (ps-print-buffer-with-faces file) + (message "Postscript written to %s" file)) + ((string-match "\\.ics\\'" file) + (let ((org-agenda-marker-table + (org-create-marker-find-array + (org-agenda-collect-markers))) + (org-icalendar-verify-function 'org-check-agenda-marker-table) + (org-combined-agenda-icalendar-file file)) + (apply 'org-export-icalendar 'combine (org-agenda-files)))) + (t + (let ((bs (buffer-string))) + (find-file file) + (insert bs) + (save-buffer 0) + (kill-buffer (current-buffer)) + (message "Plain text written to %s" file)))))) + (set-buffer org-agenda-buffer-name))) + +(defun org-agenda-collect-markers () + "Collect the markers pointing to entries in the agenda buffer." + (let (m markers) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (when (setq m (or (get-text-property (point) 'org-hd-marker) + (get-text-property (point) 'org-marker))) + (push m markers)) + (beginning-of-line 2))) + (nreverse markers))) + +(defun org-create-marker-find-array (marker-list) + "Create a alist of files names with all marker positions in that file." + (let (f tbl m a p) + (while (setq m (pop marker-list)) + (setq p (marker-position m) + f (buffer-file-name (or (buffer-base-buffer + (marker-buffer m)) + (marker-buffer m)))) + (if (setq a (assoc f tbl)) + (push (marker-position m) (cdr a)) + (push (list f p) tbl))) + (mapcar (lambda (x) (setcdr x (sort (copy-sequence (cdr x)) '<)) x) + tbl))) + +(defvar org-agenda-marker-table nil) ; dyamically scoped parameter +(defun org-check-agenda-marker-table () + "Check of the current entry is on the marker list." + (let ((file (buffer-file-name (or (buffer-base-buffer) (current-buffer)))) + a) + (and (setq a (assoc file org-agenda-marker-table)) + (save-match-data + (save-excursion + (org-back-to-heading t) + (member (point) (cdr a))))))) (defmacro org-no-read-only (&rest body) "Inhibit read-only for BODY." @@ -13431,8 +20427,10 @@ before running the agenda command." "Fit the window to the buffer size." (and (memq org-agenda-window-setup '(reorganize-frame)) (fboundp 'fit-window-to-buffer) - (fit-window-to-buffer nil (/ (* (frame-height) 3) 4) - (/ (frame-height) 2)))) + (fit-window-to-buffer + nil + (floor (* (frame-height) (cdr org-agenda-window-frame-fractions))) + (floor (* (frame-height) (car org-agenda-window-frame-fractions)))))) ;;; Agenda file list @@ -13440,11 +20438,26 @@ before running the agenda command." "Get the list of agenda files. Optional UNRESTRICTED means return the full list even if a restriction is currently in place." - (cond - ((and (not unrestricted) (get 'org-agenda-files 'org-restrict))) - ((stringp org-agenda-files) (org-read-agenda-file-list)) - ((listp org-agenda-files) org-agenda-files) - (t (error "Invalid value of `org-agenda-files'")))) + (let ((files + (cond + ((and (not unrestricted) (get 'org-agenda-files 'org-restrict))) + ((stringp org-agenda-files) (org-read-agenda-file-list)) + ((listp org-agenda-files) org-agenda-files) + (t (error "Invalid value of `org-agenda-files'"))))) + (setq files (apply 'append + (mapcar (lambda (f) + (if (file-directory-p f) + (directory-files f t + org-agenda-file-regexp) + (list f))) + files))) + (if org-agenda-skip-unavailable-files + (delq nil + (mapcar (function + (lambda (file) + (and (file-readable-p file) file))) + files)) + files))) ; `org-check-agenda-file' will remove them from the list (defun org-edit-agenda-file-list () "Edit the list of agenda files. @@ -13465,8 +20478,8 @@ the buffer and restores the previous window configuration." (org-install-agenda-files-menu) (message "New agenda file list installed")) nil 'local) - (message (substitute-command-keys - "Edit list and finish with \\[save-buffer]"))) + (message "%s" (substitute-command-keys + "Edit list and finish with \\[save-buffer]"))) (customize-variable 'org-agenda-files))) (defun org-store-new-agenda-file-list (list) @@ -13508,20 +20521,14 @@ If the current buffer does not, find the first agenda file." (find-file (car fs))) (if (buffer-base-buffer) (switch-to-buffer (buffer-base-buffer))))) -(defun org-agenda-file-to-end () - "Move/add the current file to the end of the agenda file list. -If the file is not present in the list, it is appended to the list. If it is -present, it is moved there." - (interactive) - (org-agenda-file-to-front 'to-end)) - (defun org-agenda-file-to-front (&optional to-end) "Move/add the current file to the top of the agenda file list. If the file is not present in the list, it is added to the front. If it is present, it is moved there. With optional argument TO-END, add/move to the end of the list." (interactive "P") - (let ((file-alist (mapcar (lambda (x) + (let ((org-agenda-skip-unavailable-files nil) + (file-alist (mapcar (lambda (x) (cons (file-truename x) x)) (org-agenda-files t))) (ctf (file-truename buffer-file-name)) @@ -13542,7 +20549,8 @@ end of the list." These are the files which are being checked for agenda entries. Optional argument FILE means, use this file instead of the current." (interactive) - (let* ((file (or file buffer-file-name)) + (let* ((org-agenda-skip-unavailable-files nil) + (file (or file buffer-file-name)) (true-file (file-truename file)) (afile (abbreviate-file-name file)) (files (delq nil (mapcar @@ -13556,7 +20564,7 @@ Optional argument FILE means, use this file instead of the current." (org-store-new-agenda-file-list files) (org-install-agenda-files-menu) (message "Removed file: %s" afile)) - (message "File was not in list: %s" afile)))) + (message "File was not in list: %s (not removed)" afile)))) (defun org-file-menu-entry (file) (vector file (list 'find-file file) t)) @@ -13578,16 +20586,23 @@ Optional argument FILE means, use this file instead of the current." (defvar org-agenda-multi nil) ; dynammically scoped (defvar org-agenda-buffer-name "*Org Agenda*") (defvar org-pre-agenda-window-conf nil) -(defun org-prepare-agenda () +(defvar org-agenda-name nil) +(defun org-prepare-agenda (&optional name) + (setq org-todo-keywords-for-agenda nil) + (setq org-done-keywords-for-agenda nil) (if org-agenda-multi (progn (setq buffer-read-only nil) (goto-char (point-max)) - (unless (= (point) 1) + (unless (or (bobp) org-agenda-compact-blocks) (insert "\n" (make-string (window-width) ?=) "\n")) (narrow-to-region (point) (point-max))) - (org-agenda-maybe-reset-markers 'force) + (org-agenda-reset-markers) (org-prepare-agenda-buffers (org-agenda-files)) + (setq org-todo-keywords-for-agenda + (org-uniquify org-todo-keywords-for-agenda)) + (setq org-done-keywords-for-agenda + (org-uniquify org-done-keywords-for-agenda)) (let* ((abuf (get-buffer-create org-agenda-buffer-name)) (awin (get-buffer-window abuf))) (cond @@ -13597,28 +20612,69 @@ Optional argument FILE means, use this file instead of the current." ((equal org-agenda-window-setup 'current-window) (switch-to-buffer abuf)) ((equal org-agenda-window-setup 'other-window) - (switch-to-buffer-other-window abuf)) + (org-switch-to-buffer-other-window abuf)) ((equal org-agenda-window-setup 'other-frame) (switch-to-buffer-other-frame abuf)) ((equal org-agenda-window-setup 'reorganize-frame) (delete-other-windows) - (switch-to-buffer-other-window abuf)))) + (org-switch-to-buffer-other-window abuf)))) (setq buffer-read-only nil) (erase-buffer) - (org-agenda-mode)) + (org-agenda-mode) + (and name (not org-agenda-name) + (org-set-local 'org-agenda-name name))) (setq buffer-read-only nil)) (defun org-finalize-agenda () "Finishing touch for the agenda buffer, called just before displaying it." (unless org-agenda-multi - (org-agenda-align-tags) (save-excursion - (let ((buffer-read-only)) + (let ((inhibit-read-only t)) (goto-char (point-min)) (while (org-activate-bracket-links (point-max)) (add-text-properties (match-beginning 0) (match-end 0) - '(face org-link)))) - (run-hooks 'org-finalize-agenda-hook)))) + '(face org-link))) + (org-agenda-align-tags) + (unless org-agenda-with-colors + (remove-text-properties (point-min) (point-max) '(face nil)))) + (if (and (boundp 'org-overriding-columns-format) + org-overriding-columns-format) + (org-set-local 'org-overriding-columns-format + org-overriding-columns-format)) + (if (and (boundp 'org-agenda-view-columns-initially) + org-agenda-view-columns-initially) + (org-agenda-columns)) + (when org-agenda-fontify-priorities + (org-fontify-priorities)) + (run-hooks 'org-finalize-agenda-hook) + (setq org-agenda-type (get-text-property (point) 'org-agenda-type)) + ))) + +(defun org-fontify-priorities () + "Make highest priority lines bold, and lowest italic." + (interactive) + (mapc (lambda (o) (if (eq (org-overlay-get o 'org-type) 'org-priority) + (org-delete-overlay o))) + (org-overlays-in (point-min) (point-max))) + (save-excursion + (let ((inhibit-read-only t) + b e p ov h l) + (goto-char (point-min)) + (while (re-search-forward "\\[#\\(.\\)\\]" nil t) + (setq h (or (get-char-property (point) 'org-highest-priority) + org-highest-priority) + l (or (get-char-property (point) 'org-lowest-priority) + org-lowest-priority) + p (string-to-char (match-string 1)) + b (match-beginning 0) e (point-at-eol) + ov (org-make-overlay b e)) + (org-overlay-put + ov 'face + (cond ((listp org-agenda-fontify-priorities) + (cdr (assoc p org-agenda-fontify-priorities))) + ((equal p l) 'italic) + ((equal p h) 'bold))) + (org-overlay-put ov 'org-type 'org-priority))))) (defun org-prepare-agenda-buffers (files) "Create buffers for all agenda files, protect archived trees and comments." @@ -13626,15 +20682,23 @@ Optional argument FILE means, use this file instead of the current." (let ((pa '(:org-archived t)) (pc '(:org-comment t)) (pall '(:org-archived t :org-comment t)) + (inhibit-read-only t) (rea (concat ":" org-archive-tag ":")) bmp file re) (save-excursion (save-restriction (while (setq file (pop files)) - (org-check-agenda-file file) - (set-buffer (org-get-agenda-file-buffer file)) + (if (bufferp file) + (set-buffer file) + (org-check-agenda-file file) + (set-buffer (org-get-agenda-file-buffer file))) (widen) (setq bmp (buffer-modified-p)) + (org-refresh-category-properties) + (setq org-todo-keywords-for-agenda + (append org-todo-keywords-for-agenda org-todo-keywords-1)) + (setq org-done-keywords-for-agenda + (append org-done-keywords-for-agenda org-done-keywords)) (save-excursion (remove-text-properties (point-min) (point-max) pall) (when org-agenda-skip-archived-trees @@ -13651,18 +20715,20 @@ Optional argument FILE means, use this file instead of the current." (defvar org-agenda-skip-function nil "Function to be called at each match during agenda construction. -If this function return nil, the current match should not be skipped. +If this function returns nil, the current match should not be skipped. Otherwise, the function must return a position from where the search should be continued. +This may also be a Lisp form, it will be evaluated. Never set this variable using `setq' or so, because then it will apply to all future agenda commands. Instead, bind it with `let' to scope -it dynamically into the agenda-constructing command.") +it dynamically into the agenda-constructing command. A good way to set +it is through options in org-agenda-custom-commands.") (defun org-agenda-skip () "Throw to `:skip' in places that should be skipped. Also moves point to the end of the skipped region, so that search can continue from there." - (let ((p (point-at-bol)) to) + (let ((p (point-at-bol)) to fp) (and org-agenda-skip-archived-trees (get-text-property p :org-archived) (org-end-of-subtree t) @@ -13671,10 +20737,13 @@ continue from there." (org-end-of-subtree t) (throw :skip t)) (if (equal (char-after p) ?#) (throw :skip t)) - (when (and (functionp org-agenda-skip-function) + (when (and (or (setq fp (functionp org-agenda-skip-function)) + (consp org-agenda-skip-function)) (setq to (save-excursion (save-match-data - (funcall org-agenda-skip-function))))) + (if fp + (funcall org-agenda-skip-function) + (eval org-agenda-skip-function)))))) (goto-char to) (throw :skip t)))) @@ -13692,17 +20761,10 @@ no longer in use." (push m org-agenda-markers) m)) -(defun org-agenda-maybe-reset-markers (&optional force) - "Reset markers created by `org-agenda'. But only if they are old enough." - (if (or (and force (not org-agenda-multi)) - (> (- (time-to-seconds (current-time)) - org-agenda-last-marker-time) - 5)) - (while org-agenda-markers - (move-marker (pop org-agenda-markers) nil)))) - -(defvar org-agenda-new-buffers nil - "Buffers created to visit agenda files.") +(defun org-agenda-reset-markers () + "Reset markers created by `org-agenda'." + (while org-agenda-markers + (move-marker (pop org-agenda-markers) nil))) (defun org-get-agenda-file-buffer (file) "Get a buffer visiting FILE. If the buffer needs to be created, add @@ -13728,36 +20790,14 @@ When a buffer is unmodified, it is just killed. When modified, it is saved (with-current-buffer buf (save-buffer))) (kill-buffer buf)))) -(defvar org-category-table nil) -(defun org-get-category-table () - "Get the table of categories and positions in current buffer." - (let (tbl) - (save-excursion - (goto-char (point-min)) - (while (re-search-forward "\\(^\\|\r\\)#\\+CATEGORY:[ \t]*\\(.*\\)" nil t) - (push (cons (point) (org-trim (match-string 2))) tbl))) - tbl)) - (defun org-get-category (&optional pos) "Get the category applying to position POS." - (if (not org-category-table) - (cond - ((null org-category) - (setq org-category - (if buffer-file-name - (file-name-sans-extension - (file-name-nondirectory buffer-file-name)) - "???"))) - ((symbolp org-category) (symbol-name org-category)) - (t org-category)) - (let ((tbl org-category-table) - (pos (or pos (point)))) - (while (and tbl (> (caar tbl) pos)) - (pop tbl)) - (or (cdar tbl) (cdr (nth (1- (length org-category-table)) - org-category-table)))))) + (get-text-property (or pos (point)) 'org-category)) + ;;; Agenda timeline +(defvar org-agenda-only-exact-dates nil) ; dynamically scoped + (defun org-timeline (&optional include-all) "Show a time-sorted view of the entries in the current org file. Only entries with a time stamp of today or later will be listed. With @@ -13779,29 +20819,35 @@ dates." (day-numbers (org-get-all-dates beg end 'no-ranges t doclosed ; always include today org-timeline-show-empty-dates)) + (org-deadline-warning-days 0) + (org-agenda-only-exact-dates t) (today (time-to-days (current-time))) (past t) args s e rtn d emptyp) (setq org-agenda-redo-command (list 'progn - (list 'switch-to-buffer-other-window (current-buffer)) + (list 'org-switch-to-buffer-other-window (current-buffer)) (list 'org-timeline (list 'quote include-all)))) (if (not dopast) ;; Remove past dates from the list of dates. (setq day-numbers (delq nil (mapcar (lambda(x) (if (>= x today) x nil)) day-numbers)))) - (org-prepare-agenda) + (org-prepare-agenda (concat "Timeline " + (file-name-nondirectory buffer-file-name))) (if doclosed (push :closed args)) (push :timestamp args) + (push :deadline args) + (push :scheduled args) + (push :sexp args) (if dotodo (push :todo args)) (while (setq d (pop day-numbers)) (if (and (listp d) (eq (car d) :omitted)) (progn (setq s (point)) (insert (format "\n[... %d empty days omitted]\n\n" (cdr d))) - (put-text-property s (1- (point)) 'face 'org-level-3)) + (put-text-property s (1- (point)) 'face 'org-agenda-structure)) (if (listp d) (setq d (car d) emptyp t) (setq emptyp nil)) (if (and (>= d today) dopast @@ -13812,19 +20858,17 @@ dates." (setq date (calendar-gregorian-from-absolute d)) (setq s (point)) (setq rtn (and (not emptyp) - (apply 'org-agenda-get-day-entries - entry date args))) + (apply 'org-agenda-get-day-entries entry + date args))) (if (or rtn (equal d today) org-timeline-show-empty-dates) (progn - (insert (calendar-day-name date) " " - (number-to-string (extract-calendar-day date)) " " - (calendar-month-name (extract-calendar-month date)) " " - (number-to-string (extract-calendar-year date)) "\n") -; FIXME: this gives a timezone problem -; (insert (format-time-string org-agenda-date-format -; (calendar-time-from-absolute d 0)) -; "\n") - (put-text-property s (1- (point)) 'face 'org-level-3) + (insert + (if (stringp org-agenda-format-date) + (format-time-string org-agenda-format-date + (org-time-from-absolute date)) + (funcall org-agenda-format-date date)) + "\n") + (put-text-property s (1- (point)) 'face 'org-agenda-structure) (put-text-property s (1- (point)) 'org-date-line t) (if (equal d today) (put-text-property s (1- (point)) 'org-today t)) @@ -13837,14 +20881,16 @@ dates." (org-finalize-agenda) (setq buffer-read-only t))) -(defun org-get-all-dates (beg end &optional no-ranges force-today inactive empty) +(defun org-get-all-dates (beg end &optional no-ranges force-today inactive empty pre-re) "Return a list of all relevant day numbers from BEG to END buffer positions. If NO-RANGES is non-nil, include only the start and end dates of a range, not every single day in the range. If FORCE-TODAY is non-nil, make sure that TODAY is included in the list. If INACTIVE is non-nil, also inactive time stamps (those in square brackets) are included. When EMPTY is non-nil, also include days without any entries." - (let ((re (if inactive org-ts-regexp-both org-ts-regexp)) + (let ((re (concat + (if pre-re pre-re "") + (if inactive org-ts-regexp-both org-ts-regexp))) dates dates1 date day day1 day2 ts1 ts2) (if force-today (setq dates (list (time-to-days (current-time))))) @@ -13880,41 +20926,55 @@ When EMPTY is non-nil, also include days without any entries." ;;; Agenda Daily/Weekly (defvar org-agenda-overriding-arguments nil) ; dynamically scoped parameter +(defvar org-agenda-start-day nil) ; dynamically scoped parameter (defvar org-agenda-last-arguments nil "The arguments of the previous call to org-agenda") (defvar org-starting-day nil) ; local variable in the agenda buffer +(defvar org-agenda-span nil) ; local variable in the agenda buffer (defvar org-include-all-loc nil) ; local variable - +(defvar org-agenda-remove-date nil) ; dynamically scoped FIXME: not used??? ;;;###autoload (defun org-agenda-list (&optional include-all start-day ndays) - "Produce a weekly view from all files in variable `org-agenda-files'. -The view will be for the current week, but from the overview buffer you -will be able to go to other weeks. -With one \\[universal-argument] prefix argument INCLUDE-ALL, all unfinished TODO items will -also be shown, under the current date. -With two \\[universal-argument] prefix argument INCLUDE-ALL, all TODO entries marked DONE -on the days are also shown. See the variable `org-log-done' for how -to turn on logging. + "Produce a daily/weekly view from all files in variable `org-agenda-files'. +The view will be for the current day or week, but from the overview buffer +you will be able to go to other days/weeks. + +With one \\[universal-argument] prefix argument INCLUDE-ALL, +all unfinished TODO items will also be shown, before the agenda. +This feature is considered obsolete, please use the TODO list or a block +agenda instead. + +With a numeric prefix argument in an interactive call, the agenda will +span INCLUDE-ALL days. Lisp programs should instead specify NDAYS to change +the number of days. NDAYS defaults to `org-agenda-ndays'. + START-DAY defaults to TODAY, or to the most recent match for the weekday -given in `org-agenda-start-on-weekday'. -NDAYS defaults to `org-agenda-ndays'." +given in `org-agenda-start-on-weekday'." (interactive "P") + (if (and (integerp include-all) (> include-all 0)) + (setq ndays include-all include-all nil)) + (setq ndays (or ndays org-agenda-ndays) + start-day (or start-day org-agenda-start-day)) (if org-agenda-overriding-arguments (setq include-all (car org-agenda-overriding-arguments) start-day (nth 1 org-agenda-overriding-arguments) ndays (nth 2 org-agenda-overriding-arguments))) + (if (stringp start-day) + ;; Convert to an absolute day number + (setq start-day (time-to-days (org-read-date nil t start-day)))) (setq org-agenda-last-arguments (list include-all start-day ndays)) (org-compile-prefix-format 'agenda) (org-set-sorting-strategy 'agenda) (require 'calendar) (let* ((org-agenda-start-on-weekday - (if (or (equal ndays 1) - (and (null ndays) (equal 1 org-agenda-ndays))) - nil org-agenda-start-on-weekday)) + (if (or (equal ndays 7) (and (null ndays) (equal 7 org-agenda-ndays))) + org-agenda-start-on-weekday nil)) (thefiles (org-agenda-files)) (files thefiles) - (today (time-to-days (current-time))) + (today (time-to-days + (time-subtract (current-time) + (list 0 (* 3600 org-extend-today-until) 0)))) (sd (or start-day today)) (start (if (or (null org-agenda-start-on-weekday) (< org-agenda-ndays 7)) @@ -13925,6 +20985,7 @@ NDAYS defaults to `org-agenda-ndays'." (d (- nt n1))) (- sd (+ (if (< d 0) 7 0) d))))) (day-numbers (list start)) + (day-cnt 0) (inhibit-redisplay (not debug-on-error)) s e rtn rtnall file date d start-pos end-pos todayp nd) (setq org-agenda-redo-command @@ -13936,9 +20997,11 @@ NDAYS defaults to `org-agenda-ndays'." (push (1+ (car day-numbers)) day-numbers) (setq ndays (1- ndays))) (setq day-numbers (nreverse day-numbers)) - (org-prepare-agenda) + (org-prepare-agenda "Day/Week") (org-set-local 'org-starting-day (car day-numbers)) (org-set-local 'org-include-all-loc include-all) + (org-set-local 'org-agenda-span + (org-agenda-ndays-to-span nd)) (when (and (or include-all org-agenda-include-all-todo) (member today day-numbers)) (setq files thefiles @@ -13953,11 +21016,14 @@ NDAYS defaults to `org-agenda-ndays'." (when rtnall (insert "ALL CURRENTLY OPEN TODO ITEMS:\n") (add-text-properties (point-min) (1- (point)) - (list 'face 'org-level-3)) + (list 'face 'org-agenda-structure)) (insert (org-finalize-agenda-entries rtnall) "\n"))) - (setq s (point)) - (insert (if (= nd 7) "Week-" "Day-") "agenda:\n") - (add-text-properties s (1- (point)) (list 'face 'org-level-3)) + (unless org-agenda-compact-blocks + (setq s (point)) + (insert (capitalize (symbol-name (org-agenda-ndays-to-span nd))) + "-agenda:\n") + (add-text-properties s (1- (point)) (list 'face 'org-agenda-structure + 'org-date-line t))) (while (setq d (pop day-numbers)) (setq date (calendar-gregorian-from-absolute d) s (point)) @@ -13974,10 +21040,10 @@ NDAYS defaults to `org-agenda-ndays'." (if org-agenda-show-log (setq rtn (org-agenda-get-day-entries file date - :deadline :scheduled :timestamp :closed)) + :deadline :scheduled :timestamp :sexp :closed)) (setq rtn (org-agenda-get-day-entries file date - :deadline :scheduled :timestamp))) + :deadline :scheduled :sexp :timestamp))) (setq rtnall (append rtnall rtn)))) (if org-agenda-include-diary (progn @@ -13986,23 +21052,24 @@ NDAYS defaults to `org-agenda-ndays'." (setq rtnall (append rtnall rtn)))) (if (or rtnall org-agenda-show-all-dates) (progn - (insert (format "%-9s %2d %s %4d\n" - (calendar-day-name date) - (extract-calendar-day date) - (calendar-month-name (extract-calendar-month date)) - (extract-calendar-year date))) -; FIXME: this gives a timezone problem -; (insert (format-time-string org-agenda-date-format -; (calendar-time-from-absolute d 0)) "\n") - (put-text-property s (1- (point)) 'face 'org-level-3) + (setq day-cnt (1+ day-cnt)) + (insert + (if (stringp org-agenda-format-date) + (format-time-string org-agenda-format-date + (org-time-from-absolute date)) + (funcall org-agenda-format-date date)) + "\n") + (put-text-property s (1- (point)) 'face 'org-agenda-structure) (put-text-property s (1- (point)) 'org-date-line t) + (put-text-property s (1- (point)) 'org-day-cnt day-cnt) (if todayp (put-text-property s (1- (point)) 'org-today t)) (if rtnall (insert (org-finalize-agenda-entries (org-agenda-add-time-grid-maybe rtnall nd todayp)) "\n")) - (put-text-property s (1- (point)) 'day d)))) + (put-text-property s (1- (point)) 'day d) + (put-text-property s (1- (point)) 'org-day-cnt day-cnt)))) (goto-char (point-min)) (org-fit-agenda-window) (unless (and (pos-visible-in-window-p (point-min)) @@ -14019,6 +21086,166 @@ NDAYS defaults to `org-agenda-ndays'." (setq buffer-read-only t) (message ""))) +(defun org-agenda-ndays-to-span (n) + (cond ((< n 7) 'day) ((= n 7) 'week) ((< n 32) 'month) (t 'year))) + +;;; Agenda word search + +(defvar org-agenda-search-history nil) + +;;;###autoload +(defun org-search-view (&optional arg string) + "Show all entries that contain words or regular expressions. +If the first character of the search string is an asterisks, +search only the headlines. + +The search string is broken into \"words\" by splitting at whitespace. +The individual words are then interpreted as a boolean expression with +logical AND. Words prefixed with a minus must not occur in the entry. +Words without a prefix or prefixed with a plus must occur in the entry. +Matching is case-insensitive and the words are enclosed by word delimiters. + +Words enclosed by curly braces are interpreted as regular expressions +that must or must not match in the entry. + +This command searches the agenda files, and in addition the files listed +in `org-agenda-text-search-extra-files'." + (interactive "P") + (org-compile-prefix-format 'search) + (org-set-sorting-strategy 'search) + (org-prepare-agenda "SEARCH") + (let* ((props (list 'face nil + 'done-face 'org-done + 'org-not-done-regexp org-not-done-regexp + 'org-todo-regexp org-todo-regexp + 'mouse-face 'highlight + 'keymap org-agenda-keymap + 'help-echo (format "mouse-2 or RET jump to location"))) + regexp rtn rtnall files file pos + marker priority category tags c neg re + ee txt beg end words regexps+ regexps- hdl-only buffer beg1 str) + (unless (and (not arg) + (stringp string) + (string-match "\\S-" string)) + (setq string (read-string "[+-]Word/{Regexp} ...: " + (cond + ((integerp arg) (cons string arg)) + (arg string)) + 'org-agenda-search-history))) + (setq org-agenda-redo-command + (list 'org-search-view 'current-prefix-arg string)) + (setq org-agenda-query-string string) + + (if (equal (string-to-char string) ?*) + (setq hdl-only t + words (substring string 1)) + (setq words string)) + (setq words (org-split-string words)) + (mapc (lambda (w) + (setq c (string-to-char w)) + (if (equal c ?-) + (setq neg t w (substring w 1)) + (if (equal c ?+) + (setq neg nil w (substring w 1)) + (setq neg nil))) + (if (string-match "\\`{.*}\\'" w) + (setq re (substring w 1 -1)) + (setq re (concat "\\<" (regexp-quote (downcase w)) "\\>"))) + (if neg (push re regexps-) (push re regexps+))) + words) + (setq regexps+ (sort regexps+ (lambda (a b) (> (length a) (length b))))) + (if (not regexps+) + (setq regexp (concat "^" org-outline-regexp)) + (setq regexp (pop regexps+)) + (if hdl-only (setq regexp (concat "^" org-outline-regexp ".*?" + regexp)))) + (setq files (append (org-agenda-files) org-agenda-text-search-extra-files) + rtnall nil) + (while (setq file (pop files)) + (setq ee nil) + (catch 'nextfile + (org-check-agenda-file file) + (setq buffer (if (file-exists-p file) + (org-get-agenda-file-buffer file) + (error "No such file %s" file))) + (if (not buffer) + ;; If file does not exist, make sure an error message is sent + (setq rtn (list (format "ORG-AGENDA-ERROR: No such org-file %s" + file)))) + (with-current-buffer buffer + (unless (org-mode-p) + (error "Agenda file %s is not in `org-mode'" file)) + (let ((case-fold-search t)) + (save-excursion + (save-restriction + (if org-agenda-restrict + (narrow-to-region org-agenda-restrict-begin + org-agenda-restrict-end) + (widen)) + (goto-char (point-min)) + (unless (or (org-on-heading-p) + (outline-next-heading)) + (throw 'nextfile t)) + (goto-char (max (point-min) (1- (point)))) + (while (re-search-forward regexp nil t) + (org-back-to-heading t) + (skip-chars-forward "* ") + (setq beg (point-at-bol) + beg1 (point) + end (progn (outline-next-heading) (point))) + (catch :skip + (goto-char beg) + (org-agenda-skip) + (setq str (buffer-substring-no-properties + (point-at-bol) + (if hdl-only (point-at-eol) end))) + (mapc (lambda (wr) (when (string-match wr str) + (goto-char (1- end)) + (throw :skip t))) + regexps-) + (mapc (lambda (wr) (unless (string-match wr str) + (goto-char (1- end)) + (throw :skip t))) + regexps+) + (goto-char beg) + (setq marker (org-agenda-new-marker (point)) + category (org-get-category) + tags (org-get-tags-at (point)) + txt (org-format-agenda-item + "" + (buffer-substring-no-properties + beg1 (point-at-eol)) + category tags)) + (org-add-props txt props + 'org-marker marker 'org-hd-marker marker + 'priority 1000 'org-category category + 'type "search") + (push txt ee) + (goto-char (1- end))))))))) + (setq rtn (nreverse ee)) + (setq rtnall (append rtnall rtn))) + (if org-agenda-overriding-header + (insert (org-add-props (copy-sequence org-agenda-overriding-header) + nil 'face 'org-agenda-structure) "\n") + (insert "Search words: ") + (add-text-properties (point-min) (1- (point)) + (list 'face 'org-agenda-structure)) + (setq pos (point)) + (insert string "\n") + (add-text-properties pos (1- (point)) (list 'face 'org-warning)) + (setq pos (point)) + (unless org-agenda-multi + (insert "Press `[', `]' to add/sub word, `{', `}' to add/sub regexp, `C-u r' to edit\n") + (add-text-properties pos (1- (point)) + (list 'face 'org-agenda-structure)))) + (when rtnall + (insert (org-finalize-agenda-entries rtnall) "\n")) + (goto-char (point-min)) + (org-fit-agenda-window) + (add-text-properties (point-min) (point-max) '(org-agenda-type search)) + (org-finalize-agenda) + (setq buffer-read-only t))) + ;;; Agenda TODO list (defvar org-select-this-todo-keyword nil) @@ -14030,28 +21257,27 @@ NDAYS defaults to `org-agenda-ndays'." The prefix arg can be used to select a specific TODO keyword and limit the list to these. When using \\[universal-argument], you will be prompted for a keyword. A numeric prefix directly selects the Nth keyword in -`org-todo-keywords'." +`org-todo-keywords-1'." (interactive "P") (require 'calendar) (org-compile-prefix-format 'todo) (org-set-sorting-strategy 'todo) + (org-prepare-agenda "TODO") (let* ((today (time-to-days (current-time))) (date (calendar-gregorian-from-absolute today)) - (kwds org-todo-keywords) + (kwds org-todo-keywords-for-agenda) (completion-ignore-case t) (org-select-this-todo-keyword (if (stringp arg) arg (and arg (integerp arg) (> arg 0) - (nth (1- arg) org-todo-keywords)))) + (nth (1- arg) kwds)))) rtn rtnall files file pos) (when (equal arg '(4)) (setq org-select-this-todo-keyword - (completing-read "Keyword: " (mapcar 'list org-todo-keywords) - nil t))) + (completing-read "Keyword (or KWD1|K2D2|...): " + (mapcar 'list kwds) nil nil))) (and (equal 0 arg) (setq org-select-this-todo-keyword nil)) - (org-prepare-agenda) (org-set-local 'org-last-arg arg) - (org-set-local 'org-todo-keywords kwds) (setq org-agenda-redo-command '(org-todo-list (or current-prefix-arg org-last-arg))) (setq files (org-agenda-files) @@ -14063,23 +21289,25 @@ for a keyword. A numeric prefix directly selects the Nth keyword in (setq rtnall (append rtnall rtn)))) (if org-agenda-overriding-header (insert (org-add-props (copy-sequence org-agenda-overriding-header) - nil 'face 'org-level-3) "\n") + nil 'face 'org-agenda-structure) "\n") (insert "Global list of TODO items of type: ") (add-text-properties (point-min) (1- (point)) - (list 'face 'org-level-3)) + (list 'face 'org-agenda-structure)) (setq pos (point)) (insert (or org-select-this-todo-keyword "ALL") "\n") (add-text-properties pos (1- (point)) (list 'face 'org-warning)) (setq pos (point)) (unless org-agenda-multi - (insert - "Available with `N r': (0)ALL " - (let ((n 0)) - (mapconcat (lambda (x) - (format "(%d)%s" (setq n (1+ n)) x)) - org-todo-keywords " ")) - "\n")) - (add-text-properties pos (1- (point)) (list 'face 'org-level-3))) + (insert "Available with `N r': (0)ALL") + (let ((n 0) s) + (mapc (lambda (x) + (setq s (format "(%d)%s" (setq n (1+ n)) x)) + (if (> (+ (current-column) (string-width s) 1) (frame-width)) + (insert "\n ")) + (insert " " s)) + kwds)) + (insert "\n")) + (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure))) (when rtnall (insert (org-finalize-agenda-entries rtnall) "\n")) (goto-char (point-min)) @@ -14104,10 +21332,11 @@ The prefix arg TODO-ONLY limits the search to TODO entries." buffer) (setq matcher (org-make-tags-matcher match) match (car matcher) matcher (cdr matcher)) - (org-prepare-agenda) + (org-prepare-agenda (concat "TAGS " match)) + (setq org-agenda-query-string match) (setq org-agenda-redo-command (list 'org-tags-view (list 'quote todo-only) - (list 'if 'current-prefix-arg nil match))) + (list 'if 'current-prefix-arg nil 'org-agenda-query-string))) (setq files (org-agenda-files) rtnall nil) (while (setq file (pop files)) @@ -14124,7 +21353,6 @@ The prefix arg TODO-ONLY limits the search to TODO entries." (with-current-buffer buffer (unless (org-mode-p) (error "Agenda file %s is not in `org-mode'" file)) - (setq org-category-table (org-get-category-table)) (save-excursion (save-restriction (if org-agenda-restrict @@ -14135,17 +21363,17 @@ The prefix arg TODO-ONLY limits the search to TODO entries." (setq rtnall (append rtnall rtn)))))))) (if org-agenda-overriding-header (insert (org-add-props (copy-sequence org-agenda-overriding-header) - nil 'face 'org-level-3) "\n") + nil 'face 'org-agenda-structure) "\n") (insert "Headlines with TAGS match: ") (add-text-properties (point-min) (1- (point)) - (list 'face 'org-level-3)) + (list 'face 'org-agenda-structure)) (setq pos (point)) (insert match "\n") (add-text-properties pos (1- (point)) (list 'face 'org-warning)) (setq pos (point)) (unless org-agenda-multi (insert "Press `C-u r' to search again with new search string\n")) - (add-text-properties pos (1- (point)) (list 'face 'org-level-3))) + (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure))) (when rtnall (insert (org-finalize-agenda-entries rtnall) "\n")) (goto-char (point-min)) @@ -14169,13 +21397,69 @@ used by user-defined selections using `org-agenda-skip-function'.") If yes, it returns the end position of this tree, causing agenda commands to skip this subtree. This is a function that can be put into `org-agenda-skip-function' for the duration of a command." - (save-match-data - (let ((end (save-excursion (org-end-of-subtree t))) - skip) - (save-excursion - (setq skip (re-search-forward org-agenda-skip-regexp end t))) - (and skip end)))) + (let ((end (save-excursion (org-end-of-subtree t))) + skip) + (save-excursion + (setq skip (re-search-forward org-agenda-skip-regexp end t))) + (and skip end))) +(defun org-agenda-skip-entry-if (&rest conditions) + "Skip entry if any of CONDITIONS is true. +See `org-agenda-skip-if' for details." + (org-agenda-skip-if nil conditions)) + +(defun org-agenda-skip-subtree-if (&rest conditions) + "Skip entry if any of CONDITIONS is true. +See `org-agenda-skip-if' for details." + (org-agenda-skip-if t conditions)) + +(defun org-agenda-skip-if (subtree conditions) + "Checks current entity for CONDITIONS. +If SUBTREE is non-nil, the entire subtree is checked. Otherwise, only +the entry, i.e. the text before the next heading is checked. + +CONDITIONS is a list of symbols, boolean OR is used to combine the results +from different tests. Valid conditions are: + +scheduled Check if there is a scheduled cookie +notscheduled Check if there is no scheduled cookie +deadline Check if there is a deadline +notdeadline Check if there is no deadline +regexp Check if regexp matches +notregexp Check if regexp does not match. + +The regexp is taken from the conditions list, it must come right after +the `regexp' or `notregexp' element. + +If any of these conditions is met, this function returns the end point of +the entity, causing the search to continue from there. This is a function +that can be put into `org-agenda-skip-function' for the duration of a command." + (let (beg end m) + (org-back-to-heading t) + (setq beg (point) + end (if subtree + (progn (org-end-of-subtree t) (point)) + (progn (outline-next-heading) (1- (point))))) + (goto-char beg) + (and + (or + (and (memq 'scheduled conditions) + (re-search-forward org-scheduled-time-regexp end t)) + (and (memq 'notscheduled conditions) + (not (re-search-forward org-scheduled-time-regexp end t))) + (and (memq 'deadline conditions) + (re-search-forward org-deadline-time-regexp end t)) + (and (memq 'notdeadline conditions) + (not (re-search-forward org-deadline-time-regexp end t))) + (and (setq m (memq 'regexp conditions)) + (stringp (nth 1 m)) + (re-search-forward (nth 1 m) end t)) + (and (setq m (memq 'notregexp conditions)) + (stringp (nth 1 m)) + (not (re-search-forward (nth 1 m) end t)))) + end))) + +;;;###autoload (defun org-agenda-list-stuck-projects (&rest ignore) "Create agenda view for projects that are stuck. Stuck projects are project that have no next actions. For the definitions @@ -14184,24 +21468,38 @@ of what a project is and how to check if it stuck, customize the variable MATCH is being ignored." (interactive) (let* ((org-agenda-skip-function 'org-agenda-skip-subtree-when-regexp-matches) + ;; FIXME: we could have used org-agenda-skip-if here. (org-agenda-overriding-header "List of stuck projects: ") (matcher (nth 0 org-stuck-projects)) (todo (nth 1 org-stuck-projects)) - (tags (nth 2 org-stuck-projects)) + (todo-wds (if (member "*" todo) + (progn + (org-prepare-agenda-buffers (org-agenda-files)) + (org-delete-all + org-done-keywords-for-agenda + (copy-sequence org-todo-keywords-for-agenda))) + todo)) (todo-re (concat "^\\*+[ \t]+\\(" - (mapconcat 'identity todo "\\|") + (mapconcat 'identity todo-wds "\\|") "\\)\\>")) - (tags-re (concat "^\\*+.*:\\(" - (mapconcat 'identity tags "\\|") - "\\):[a-zA-Z0-9_@:]*[ \t]*$"))) - + (tags (nth 2 org-stuck-projects)) + (tags-re (if (member "*" tags) + (org-re "^\\*+ .*:[[:alnum:]_@]+:[ \t]*$") + (concat "^\\*+ .*:\\(" + (mapconcat 'identity tags "\\|") + (org-re "\\):[[:alnum:]_@:]*[ \t]*$")))) + (gen-re (nth 3 org-stuck-projects)) + (re-list + (delq nil + (list + (if todo todo-re) + (if tags tags-re) + (and gen-re (stringp gen-re) (string-match "\\S-" gen-re) + gen-re))))) (setq org-agenda-skip-regexp - (cond - ((and todo tags) - (concat todo-re "\\|" tags-re)) - (todo todo-re) - (tags tags-re) - (t (error "No information how to identify unstuck projects")))) + (if re-list + (mapconcat 'identity re-list "\\|") + (error "No information how to identify unstuck projects"))) (org-tags-view nil matcher) (with-current-buffer org-agenda-buffer-name (setq org-agenda-redo-command @@ -14211,11 +21509,15 @@ MATCH is being ignored." ;;; Diary integration (defvar org-disable-agenda-to-diary nil) ;Dynamically-scoped param. +(defvar list-diary-entries-hook) (defun org-get-entries-from-diary (date) "Get the (Emacs Calendar) diary entries for DATE." - (let* ((fancy-diary-buffer "*temporary-fancy-diary-buffer*") + (require 'diary-lib) + (let* ((diary-fancy-buffer "*temporary-fancy-diary-buffer*") + (fancy-diary-buffer diary-fancy-buffer) (diary-display-hook '(fancy-diary-display)) + (pop-up-frames nil) (list-diary-entries-hook (cons 'org-diary-default-entry list-diary-entries-hook)) (diary-file-name-prefix-function nil) ; turn this feature off @@ -14224,22 +21526,24 @@ MATCH is being ignored." (org-disable-agenda-to-diary t)) (save-excursion (save-window-excursion - (list-diary-entries date 1))) ;; Keep this name for now, compatibility - (if (not (get-buffer fancy-diary-buffer)) + (funcall (if (fboundp 'diary-list-entries) + 'diary-list-entries 'list-diary-entries) + date 1))) + (if (not (get-buffer diary-fancy-buffer)) (setq entries nil) - (with-current-buffer fancy-diary-buffer + (with-current-buffer diary-fancy-buffer (setq buffer-read-only nil) - (if (= (point-max) 1) + (if (zerop (buffer-size)) ;; No entries (setq entries nil) ;; Omit the date and other unnecessary stuff (org-agenda-cleanup-fancy-diary) ;; Add prefix to each line and extend the text properties - (if (= (point-max) 1) + (if (zerop (buffer-size)) (setq entries nil) (setq entries (buffer-substring (point-min) (- (point-max) 1))))) (set-buffer-modified-p nil) - (kill-buffer fancy-diary-buffer))) + (kill-buffer diary-fancy-buffer))) (when entries (setq entries (org-split-string entries "\n")) (setq entries @@ -14247,7 +21551,8 @@ MATCH is being ignored." (lambda (x) (setq x (org-format-agenda-item "" x "Diary" nil 'time)) ;; Extend the text properties to the beginning of the line - (org-add-props x (text-properties-at (1- (length x)) x))) + (org-add-props x (text-properties-at (1- (length x)) x) + 'type "diary" 'date date)) entries))))) (defun org-agenda-cleanup-fancy-diary () @@ -14289,8 +21594,10 @@ date. It also removes lines that contain only whitespace." (org-add-props string nil 'mouse-face 'highlight 'keymap org-agenda-keymap - 'help-echo (format "mouse-2 or RET jump to diary file %s" - (abbreviate-file-name buffer-file-name)) + 'help-echo (if buffer-file-name + (format "mouse-2 or RET jump to diary file %s" + (abbreviate-file-name buffer-file-name)) + "") 'org-agenda-diary-link t 'org-marker (org-agenda-new-marker (point-at-bol)))) @@ -14316,6 +21623,8 @@ items should be listed. The following arguments are allowed: date range matching the selected date. Deadlines will also be listed, on the expiration day. + :sexp List entries resulting from diary-like sexps. + :deadline List any deadlines past due, or due within `org-deadline-warning-days'. The listing occurs only in the diary for *today*, not at any other date. If @@ -14340,22 +21649,26 @@ all files listed in `org-agenda-files' will be checked automatically: &%%(org-diary) If you don't give any arguments (as in the example above), the default -arguments (:deadline :scheduled :timestamp) are used. So the example above may -also be written as +arguments (:deadline :scheduled :timestamp :sexp) are used. +So the example above may also be written as - &%%(org-diary :deadline :timestamp :scheduled) + &%%(org-diary :deadline :timestamp :sexp :scheduled) The function expects the lisp variables `entry' and `date' to be provided by the caller, because this is how the calendar works. Don't use this function from a program - use `org-agenda-get-day-entries' instead." - (org-agenda-maybe-reset-markers) + (when (> (- (time-to-seconds (current-time)) + org-agenda-last-marker-time) + 5) + (org-agenda-reset-markers)) (org-compile-prefix-format 'agenda) (org-set-sorting-strategy 'agenda) - (setq args (or args '(:deadline :scheduled :timestamp))) + (setq args (or args '(:deadline :scheduled :timestamp :sexp))) (let* ((files (if (and entry (stringp entry) (string-match "\\S-" entry)) (list entry) (org-agenda-files t))) file rtn results) + (org-prepare-agenda-buffers files) ;; If this is called during org-agenda, don't return any entries to ;; the calendar. Org Agenda will list these entries itself. (if org-disable-agenda-to-diary (setq files nil)) @@ -14373,7 +21686,7 @@ FILE is the path to a file to be checked for entries. DATE is date like the one returned by `calendar-current-date'. ARGS are symbols indicating which kind of entries should be extracted. For details about these, see the documentation of `org-diary'." - (setq args (or args '(:deadline :scheduled :timestamp))) + (setq args (or args '(:deadline :scheduled :timestamp :sexp))) (let* ((org-startup-folded nil) (org-startup-align-all-tables nil) (buffer (if (file-exists-p file) @@ -14386,7 +21699,6 @@ the documentation of `org-diary'." (with-current-buffer buffer (unless (org-mode-p) (error "Agenda file %s is not in `org-mode'" file)) - (setq org-category-table (org-get-category-table)) (let ((case-fold-search nil)) (save-excursion (save-restriction @@ -14406,23 +21718,32 @@ the documentation of `org-diary'." (setq results (append results rtn)) (setq rtn (org-agenda-get-timestamps)) (setq results (append results rtn))) + ((eq arg :sexp) + (setq rtn (org-agenda-get-sexps)) + (setq results (append results rtn))) ((eq arg :scheduled) (setq rtn (org-agenda-get-scheduled)) (setq results (append results rtn))) ((eq arg :closed) (setq rtn (org-agenda-get-closed)) (setq results (append results rtn))) - ((and (eq arg :deadline) - (equal date (calendar-current-date))) + ((eq arg :deadline) (setq rtn (org-agenda-get-deadlines)) (setq results (append results rtn)))))))) results)))) +(defun org-entry-is-todo-p () + (member (org-get-todo-state) org-not-done-keywords)) + (defun org-entry-is-done-p () - "Is the current entry marked DONE?" + (member (org-get-todo-state) org-done-keywords)) + +(defun org-get-todo-state () (save-excursion - (and (re-search-backward "[\r\n]\\*" nil t) - (looking-at org-nl-done-regexp)))) + (org-back-to-heading t) + (and (looking-at org-todo-line-regexp) + (match-end 2) + (match-string 2)))) (defun org-at-date-range-p (&optional inactive-ok) "Is the cursor inside a date range?" @@ -14447,15 +21768,20 @@ the documentation of `org-diary'." (let* ((props (list 'face nil 'done-face 'org-done 'org-not-done-regexp org-not-done-regexp + 'org-todo-regexp org-todo-regexp 'mouse-face 'highlight 'keymap org-agenda-keymap 'help-echo (format "mouse-2 or RET jump to org file %s" (abbreviate-file-name buffer-file-name)))) - (regexp (concat "[\n\r]\\*+ *\\(" + ;; FIXME: get rid of the \n at some point but watch out + (regexp (concat "^\\*+[ \t]+\\(" (if org-select-this-todo-keyword - (concat "\\<\\(" org-select-this-todo-keyword - "\\)\\>") + (if (equal org-select-this-todo-keyword "*") + org-todo-regexp + (concat "\\<\\(" + (mapconcat 'identity (org-split-string org-select-this-todo-keyword "|") "\\|") + "\\)\\>")) org-not-done-regexp) "[^\n\r]*\\)")) marker priority category tags @@ -14466,31 +21792,28 @@ the documentation of `org-diary'." (save-match-data (beginning-of-line) (setq beg (point) end (progn (outline-next-heading) (point))) - (when (or (and org-agenda-todo-ignore-scheduled (goto-char beg) + (when (or (and org-agenda-todo-ignore-with-date (goto-char beg) + (re-search-forward org-ts-regexp end t)) + (and org-agenda-todo-ignore-scheduled (goto-char beg) (re-search-forward org-scheduled-time-regexp end t)) (and org-agenda-todo-ignore-deadlines (goto-char beg) (re-search-forward org-deadline-time-regexp end t) (org-deadline-close (match-string 1)))) - (goto-char beg) + (goto-char (1+ beg)) (or org-agenda-todo-list-sublevels (org-end-of-subtree 'invisible)) (throw :skip nil))) (goto-char beg) (org-agenda-skip) (goto-char (match-beginning 1)) - (setq marker (org-agenda-new-marker (1+ (match-beginning 0))) + (setq marker (org-agenda-new-marker (match-beginning 0)) category (org-get-category) tags (org-get-tags-at (point)) txt (org-format-agenda-item "" (match-string 1) category tags) - priority - (+ (org-get-priority txt) - (if org-todo-kwd-priority-p - (- org-todo-kwd-max-priority -2 - (length - (member (match-string 2) org-todo-keywords))) - 1))) + priority (1+ (org-get-priority txt))) (org-add-props txt props 'org-marker marker 'org-hd-marker marker - 'priority priority 'org-category category) + 'priority priority 'org-category category + 'type "todo") (push txt ee) (if org-agenda-todo-list-sublevels (goto-char (match-end 1)) @@ -14504,76 +21827,128 @@ the documentation of `org-diary'." "Return the date stamp information for agenda display." (let* ((props (list 'face nil 'org-not-done-regexp org-not-done-regexp + 'org-todo-regexp org-todo-regexp 'mouse-face 'highlight 'keymap org-agenda-keymap 'help-echo (format "mouse-2 or RET jump to org file %s" (abbreviate-file-name buffer-file-name)))) - (regexp (regexp-quote - (substring - (format-time-string - (car org-time-stamp-formats) - (apply 'encode-time ; DATE bound by calendar - (list 0 0 0 (nth 1 date) (car date) (nth 2 date)))) - 0 11))) + (d1 (calendar-absolute-from-gregorian date)) + (remove-re + (concat + (regexp-quote + (format-time-string + "<%Y-%m-%d" + (encode-time 0 0 0 (nth 1 date) (nth 0 date) (nth 2 date)))) + ".*?>")) + (regexp + (concat + (regexp-quote + (substring + (format-time-string + (car org-time-stamp-formats) + (apply 'encode-time ; DATE bound by calendar + (list 0 0 0 (nth 1 date) (car date) (nth 2 date)))) + 0 11)) + "\\|\\(<[0-9]+-[0-9]+-[0-9]+[^>\n]+?\\+[0-9]+[dwmy]>\\)" + "\\|\\(<%%\\(([^>\n]+)\\)>\\)")) marker hdmarker deadlinep scheduledp donep tmp priority category - ee txt timestr tags) + ee txt timestr tags b0 b3 e3 head) (goto-char (point-min)) (while (re-search-forward regexp nil t) + (setq b0 (match-beginning 0) + b3 (match-beginning 3) e3 (match-end 3)) (catch :skip - (and (save-match-data (org-at-date-range-p)) (throw :skip nil)) + (and (org-at-date-range-p) (throw :skip nil)) (org-agenda-skip) - (setq marker (org-agenda-new-marker (match-beginning 0)) - category (org-get-category (match-beginning 0)) + (if (and (match-end 1) + (not (= d1 (org-time-string-to-absolute (match-string 1) d1)))) + (throw :skip nil)) + (if (and e3 + (not (org-diary-sexp-entry (buffer-substring b3 e3) "" date))) + (throw :skip nil)) + (setq marker (org-agenda-new-marker b0) + category (org-get-category b0) tmp (buffer-substring (max (point-min) - (- (match-beginning 0) - org-ds-keyword-length)) - (match-beginning 0)) - timestr (buffer-substring (match-beginning 0) (point-at-eol)) + (- b0 org-ds-keyword-length)) + b0) + timestr (if b3 "" (buffer-substring b0 (point-at-eol))) deadlinep (string-match org-deadline-regexp tmp) scheduledp (string-match org-scheduled-regexp tmp) donep (org-entry-is-done-p)) - (and org-agenda-skip-scheduled-if-done - scheduledp donep - (throw :skip t)) + (if (or scheduledp deadlinep) (throw :skip t)) (if (string-match ">" timestr) ;; substring should only run to end of time stamp (setq timestr (substring timestr 0 (match-end 0)))) (save-excursion - (if (re-search-backward "\\(^\\|\r\\)\\*+" nil t) + (if (re-search-backward "^\\*+ " nil t) (progn - (goto-char (match-end 1)) + (goto-char (match-beginning 0)) (setq hdmarker (org-agenda-new-marker) tags (org-get-tags-at)) - (looking-at "\\*+[ \t]*\\([^\r\n]+\\)") + (looking-at "\\*+[ \t]+\\([^\r\n]+\\)") + (setq head (match-string 1)) + (and org-agenda-skip-timestamp-if-done donep (throw :skip t)) (setq txt (org-format-agenda-item - (format "%s%s" - (if deadlinep "Deadline: " "") - (if scheduledp "Scheduled: " "")) - (match-string 1) category tags timestr))) + nil head category tags timestr nil + remove-re))) (setq txt org-agenda-no-heading-message)) (setq priority (org-get-priority txt)) (org-add-props txt props 'org-marker marker 'org-hd-marker hdmarker) - (if deadlinep - (org-add-props txt nil - 'face (if donep 'org-done 'org-warning) - 'undone-face 'org-warning 'done-face 'org-done - 'org-category category 'priority (+ 100 priority)) - (if scheduledp - (org-add-props txt nil - 'face 'org-scheduled-today - 'undone-face 'org-scheduled-today 'done-face 'org-done - 'org-category category 'priority (+ 99 priority)) - (org-add-props txt nil 'priority priority 'org-category category))) + (org-add-props txt nil 'priority priority + 'org-category category 'date date + 'type "timestamp") (push txt ee)) (outline-next-heading))) (nreverse ee))) +(defun org-agenda-get-sexps () + "Return the sexp information for agenda display." + (require 'diary-lib) + (let* ((props (list 'face nil + 'mouse-face 'highlight + 'keymap org-agenda-keymap + 'help-echo + (format "mouse-2 or RET jump to org file %s" + (abbreviate-file-name buffer-file-name)))) + (regexp "^&?%%(") + marker category ee txt tags entry result beg b sexp sexp-entry) + (goto-char (point-min)) + (while (re-search-forward regexp nil t) + (catch :skip + (org-agenda-skip) + (setq beg (match-beginning 0)) + (goto-char (1- (match-end 0))) + (setq b (point)) + (forward-sexp 1) + (setq sexp (buffer-substring b (point))) + (setq sexp-entry (if (looking-at "[ \t]*\\(\\S-.*\\)") + (org-trim (match-string 1)) + "")) + (setq result (org-diary-sexp-entry sexp sexp-entry date)) + (when result + (setq marker (org-agenda-new-marker beg) + category (org-get-category beg)) + + (if (string-match "\\S-" result) + (setq txt result) + (setq txt "SEXP entry returned empty string")) + + (setq txt (org-format-agenda-item + "" txt category tags 'time)) + (org-add-props txt props 'org-marker marker) + (org-add-props txt nil + 'org-category category 'date date + 'type "sexp") + (push txt ee)))) + (nreverse ee))) + (defun org-agenda-get-closed () "Return the logged TODO entries for agenda display." (let* ((props (list 'mouse-face 'highlight 'org-not-done-regexp org-not-done-regexp + 'org-todo-regexp org-todo-regexp 'keymap org-agenda-keymap 'help-echo (format "mouse-2 or RET jump to org file %s" @@ -14603,12 +21978,12 @@ the documentation of `org-diary'." ;; substring should only run to end of time stamp (setq timestr (substring timestr 0 (match-end 0)))) (save-excursion - (if (re-search-backward "\\(^\\|\r\\)\\*+" nil t) + (if (re-search-backward "^\\*+ " nil t) (progn - (goto-char (match-end 1)) + (goto-char (match-beginning 0)) (setq hdmarker (org-agenda-new-marker) tags (org-get-tags-at)) - (looking-at "\\*+[ \t]*\\([^\r\n]+\\)") + (looking-at "\\*+[ \t]+\\([^\r\n]+\\)") (setq txt (org-format-agenda-item (if closedp "Closed: " "Clocked: ") (match-string 1) category tags timestr))) @@ -14617,16 +21992,17 @@ the documentation of `org-diary'." (org-add-props txt props 'org-marker marker 'org-hd-marker hdmarker 'face 'org-done 'priority priority 'org-category category + 'type "closed" 'date date 'undone-face 'org-warning 'done-face 'org-done) (push txt ee)) - (outline-next-heading))) + (goto-char (point-at-eol)))) (nreverse ee))) (defun org-agenda-get-deadlines () "Return the deadline information for agenda display." - (let* ((wdays org-deadline-warning-days) - (props (list 'mouse-face 'highlight + (let* ((props (list 'mouse-face 'highlight 'org-not-done-regexp org-not-done-regexp + 'org-todo-regexp org-todo-regexp 'keymap org-agenda-keymap 'help-echo (format "mouse-2 or RET jump to org file %s" @@ -14634,54 +22010,80 @@ the documentation of `org-diary'." (regexp org-deadline-time-regexp) (todayp (equal date (calendar-current-date))) ; DATE bound by calendar (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar - d2 diff pos pos1 category tags - ee txt head face) + d2 diff dfrac wdays pos pos1 category tags + ee txt head face s upcomingp donep timestr) (goto-char (point-min)) (while (re-search-forward regexp nil t) (catch :skip (org-agenda-skip) - (setq pos (1- (match-beginning 1)) - d2 (time-to-days - (org-time-string-to-time (match-string 1))) - diff (- d2 d1)) + (setq s (match-string 1) + pos (1- (match-beginning 1)) + d2 (org-time-string-to-absolute (match-string 1) d1 'past) + diff (- d2 d1) + wdays (org-get-wdays s) + dfrac (/ (* 1.0 (- wdays diff)) (max wdays 1)) + upcomingp (and todayp (> diff 0))) ;; When to show a deadline in the calendar: ;; If the expiration is within wdays warning time. ;; Past-due deadlines are only shown on the current date - (if (and (< diff wdays) todayp (not (= diff 0))) + (if (or (and (<= diff wdays) + (and todayp (not org-agenda-only-exact-dates))) + (= diff 0)) (save-excursion (setq category (org-get-category)) - (if (re-search-backward "\\(^\\|\r\\)\\*+[ \t]*" nil t) + (if (re-search-backward "^\\*+[ \t]+" nil t) (progn (goto-char (match-end 0)) - (setq pos1 (match-end 1)) + (setq pos1 (match-beginning 0)) (setq tags (org-get-tags-at pos1)) (setq head (buffer-substring-no-properties (point) (progn (skip-chars-forward "^\r\n") (point)))) - (if (string-match org-looking-at-done-regexp head) + (setq donep (string-match org-looking-at-done-regexp head)) + (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s) + (setq timestr + (concat (substring s (match-beginning 1)) " ")) + (setq timestr 'time)) + (if (and donep + (or org-agenda-skip-deadline-if-done + (not (= diff 0)))) (setq txt nil) (setq txt (org-format-agenda-item - (format "In %3d d.: " diff) head category tags)))) + (if (= diff 0) + (car org-agenda-deadline-leaders) + (format (nth 1 org-agenda-deadline-leaders) + diff)) + head category tags timestr)))) (setq txt org-agenda-no-heading-message)) (when txt - (setq face (cond ((<= diff 0) 'org-warning) - ((<= diff 5) 'org-upcoming-deadline) - (t nil))) + (setq face (org-agenda-deadline-face dfrac wdays)) (org-add-props txt props 'org-marker (org-agenda-new-marker pos) 'org-hd-marker (org-agenda-new-marker pos1) - 'priority (+ (- 10 diff) (org-get-priority txt)) + 'priority (+ (- diff) + (org-get-priority txt)) 'org-category category - 'face face 'undone-face face 'done-face 'org-done) + 'type (if upcomingp "upcoming-deadline" "deadline") + 'date (if upcomingp date d2) + 'face (if donep 'org-done face) + 'undone-face face 'done-face 'org-done) (push txt ee)))))) - ee)) + (nreverse ee))) + +(defun org-agenda-deadline-face (fraction &optional wdays) + "Return the face to displaying a deadline item. +FRACTION is what fraction of the head-warning time has passed." + (if (equal wdays 0) (setq fraction 1.)) + (let ((faces org-agenda-deadline-faces) f) + (catch 'exit + (while (setq f (pop faces)) + (if (>= fraction (car f)) (throw 'exit (cdr f))))))) (defun org-agenda-get-scheduled () "Return the scheduled information for agenda display." - (let* ((props (list 'face 'org-scheduled-previously - 'org-not-done-regexp org-not-done-regexp - 'undone-face 'org-scheduled-previously + (let* ((props (list 'org-not-done-regexp org-not-done-regexp + 'org-todo-regexp org-todo-regexp 'done-face 'org-done 'mouse-face 'highlight 'keymap org-agenda-keymap @@ -14692,47 +22094,71 @@ the documentation of `org-diary'." (todayp (equal date (calendar-current-date))) ; DATE bound by calendar (d1 (calendar-absolute-from-gregorian date)) ; DATE bound by calendar d2 diff pos pos1 category tags - ee txt head) + ee txt head pastschedp donep face timestr s) (goto-char (point-min)) (while (re-search-forward regexp nil t) (catch :skip (org-agenda-skip) - (setq pos (1- (match-beginning 1)) - d2 (time-to-days - (org-time-string-to-time (match-string 1))) + (setq s (match-string 1) + pos (1- (match-beginning 1)) + d2 (org-time-string-to-absolute (match-string 1) d1 'past) +;;; is this right? +;;; do we need to do this for deadleine too???? +;;; d2 (org-time-string-to-absolute (match-string 1) (if todayp nil d1)) diff (- d2 d1)) + (setq pastschedp (and todayp (< diff 0))) ;; When to show a scheduled item in the calendar: ;; If it is on or past the date. - (if (and (< diff 0) todayp) + (if (or (and (< diff 0) + (and todayp (not org-agenda-only-exact-dates))) + (= diff 0)) (save-excursion (setq category (org-get-category)) - (if (re-search-backward "\\(^\\|\r\\)\\*+[ \t]*" nil t) + (if (re-search-backward "^\\*+[ \t]+" nil t) (progn (goto-char (match-end 0)) - (setq pos1 (match-end 1)) + (setq pos1 (match-beginning 0)) (setq tags (org-get-tags-at)) (setq head (buffer-substring-no-properties (point) (progn (skip-chars-forward "^\r\n") (point)))) - (if (string-match org-looking-at-done-regexp head) + (setq donep (string-match org-looking-at-done-regexp head)) + (if (string-match " \\([012]?[0-9]:[0-9][0-9]\\)" s) + (setq timestr + (concat (substring s (match-beginning 1)) " ")) + (setq timestr 'time)) + (if (and donep + (or org-agenda-skip-scheduled-if-done + (not (= diff 0)))) (setq txt nil) (setq txt (org-format-agenda-item - (format "Sched.%2dx: " (- 1 diff)) head - category tags)))) + (if (= diff 0) + (car org-agenda-scheduled-leaders) + (format (nth 1 org-agenda-scheduled-leaders) + (- 1 diff))) + head category tags timestr)))) (setq txt org-agenda-no-heading-message)) (when txt + (setq face (if pastschedp + 'org-scheduled-previously + 'org-scheduled-today)) (org-add-props txt props + 'undone-face face + 'face (if donep 'org-done face) 'org-marker (org-agenda-new-marker pos) 'org-hd-marker (org-agenda-new-marker pos1) - 'priority (+ (- 5 diff) (org-get-priority txt)) + 'type (if pastschedp "past-scheduled" "scheduled") + 'date (if pastschedp d2 date) + 'priority (+ 94 (- 5 diff) (org-get-priority txt)) 'org-category category) (push txt ee)))))) - ee)) + (nreverse ee))) (defun org-agenda-get-blocks () "Return the date-range information for agenda display." (let* ((props (list 'face nil 'org-not-done-regexp org-not-done-regexp + 'org-todo-regexp org-todo-regexp 'mouse-face 'highlight 'keymap org-agenda-keymap 'help-echo @@ -14740,7 +22166,8 @@ the documentation of `org-diary'." (abbreviate-file-name buffer-file-name)))) (regexp org-tr-regexp) (d0 (calendar-absolute-from-gregorian date)) - marker hdmarker ee txt d1 d2 s1 s2 timestr category tags pos) + marker hdmarker ee txt d1 d2 s1 s2 timestr category tags pos + donep head) (goto-char (point-min)) (while (re-search-forward regexp nil t) (catch :skip @@ -14757,20 +22184,25 @@ the documentation of `org-diary'." (save-excursion (setq marker (org-agenda-new-marker (point))) (setq category (org-get-category)) - (if (re-search-backward "\\(^\\|\r\\)\\*+" nil t) + (if (re-search-backward "^\\*+ " nil t) (progn - (setq hdmarker (org-agenda-new-marker (match-end 1))) - (goto-char (match-end 1)) + (goto-char (match-beginning 0)) + (setq hdmarker (org-agenda-new-marker (point))) (setq tags (org-get-tags-at)) - (looking-at "\\*+[ \t]*\\([^\r\n]+\\)") + (looking-at "\\*+[ \t]+\\([^\r\n]+\\)") + (setq head (match-string 1)) + (and org-agenda-skip-timestamp-if-done + (org-entry-is-done-p) + (throw :skip t)) (setq txt (org-format-agenda-item (format (if (= d1 d2) "" "(%d/%d): ") (1+ (- d0 d1)) (1+ (- d2 d1))) - (match-string 1) category tags + head category tags (if (= d0 d1) timestr)))) (setq txt org-agenda-no-heading-message)) (org-add-props txt props 'org-marker marker 'org-hd-marker hdmarker + 'type "block" 'date date 'priority (org-get-priority txt) 'org-category category) (push txt ee))) (goto-char pos))) @@ -14779,7 +22211,6 @@ the documentation of `org-diary'." ;;; Agenda presentation and sorting -;; FIXME: should I allow spaces around the dash? (defconst org-plain-time-of-day-regexp (concat "\\(\\<[012]?[0-9]" @@ -14795,10 +22226,22 @@ groups carry important information: 1 the first time, range or not 8 the second time, if it is a range.") +(defconst org-plain-time-extension-regexp + (concat + "\\(\\<[012]?[0-9]" + "\\(\\(:\\([0-5][0-9]\\([AaPp][Mm]\\)?\\)\\)\\|\\([AaPp][Mm]\\)\\)\\>\\)" + "\\+\\([0-9]+\\)\\(:\\([0-5][0-9]\\)\\)?") + "Regular expression to match a time range like 13:30+2:10 = 13:30-15:40. +Examples: 11:45 or 8am-13:15 or 2:45-2:45pm. After a match, the following +groups carry important information: +0 the full match +7 hours of duration +9 minutes of duration") + (defconst org-stamp-time-of-day-regexp (concat "<\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} +\\sw+ +\\)" - "\\([012][0-9]:[0-5][0-9]\\)>" + "\\([012][0-9]:[0-5][0-9]\\(-\\([012][0-9]:[0-5][0-9]\\)\\)?[^\n\r>]*?\\)>" "\\(--?" "<\\1\\([012][0-9]:[0-5][0-9]\\)>\\)?") "Regular expression to match a timestamp time or time range. @@ -14816,7 +22259,7 @@ The flag is set if the currently compiled format contains a `%t'.") The flag is set if the currently compiled format contains a `%T'.") (defun org-format-agenda-item (extra txt &optional category tags dotime - noprefix) + noprefix remove-re) "Format TXT to be inserted into the agenda buffer. In particular, it adds the prefix and corresponding text properties. EXTRA must be a string and replaces the `%s' specifier in the prefix format. @@ -14827,7 +22270,8 @@ time-of-day should be extracted from TXT for sorting of this entry, and for the `%t' specifier in the format. When DOTIME is a string, this string is searched for a time before TXT is. NOPREFIX is a flag and indicates that only the correctly processes TXT should be returned - this is used by -`org-agenda-change-all-lines'. TAGS can be the tags of the headline." +`org-agenda-change-all-lines'. TAGS can be the tags of the headline. +Any match of REMOVE-RE will be removed from TXT." (save-match-data ;; Diary entries sometimes have extra whitespace at the beginning (if (string-match "^ +" txt) (setq txt (replace-match "" nil nil txt))) @@ -14841,20 +22285,22 @@ only the correctly processes TXT should be returned - this is used by time ; time and tag are needed for the eval of the prefix format (ts (if dotime (concat (if (stringp dotime) dotime "") txt))) (time-of-day (and dotime (org-get-time-of-day ts))) - stamp plain s0 s1 s2 rtn) + stamp plain s0 s1 s2 rtn srp) (when (and dotime time-of-day org-prefix-has-time) ;; Extract starting and ending time and move them to prefix (when (or (setq stamp (string-match org-stamp-time-of-day-regexp ts)) (setq plain (string-match org-plain-time-of-day-regexp ts))) (setq s0 (match-string 0 ts) + srp (and stamp (match-end 3)) s1 (match-string (if plain 1 2) ts) - s2 (match-string (if plain 8 4) ts)) + s2 (match-string (if plain 8 (if srp 4 6)) ts)) ;; If the times are in TXT (not in DOTIMES), and the prefix will list ;; them, we might want to remove them there to avoid duplication. ;; The user can turn this off with a variable. (if (and org-agenda-remove-times-when-in-prefix (or stamp plain) (string-match (concat (regexp-quote s0) " *") txt) + (not (equal ?\] (string-to-char (substring txt (match-end 0))))) (if (eq org-agenda-remove-times-when-in-prefix 'beg) (= (match-beginning 0) 0) t)) @@ -14863,10 +22309,20 @@ only the correctly processes TXT should be returned - this is used by (if s1 (setq s1 (org-get-time-of-day s1 'string t))) (if s2 (setq s2 (org-get-time-of-day s2 'string t)))) - (when (string-match "\\([ \t]+\\)\\(:[a-zA-Z_@0-9:]+:\\)[ \t]*$" txt) + (when (and s1 (not s2) org-agenda-default-appointment-duration + (string-match "\\([0-9]+\\):\\([0-9]+\\)" s1)) + (let ((m (+ (string-to-number (match-string 2 s1)) + (* 60 (string-to-number (match-string 1 s1))) + org-agenda-default-appointment-duration)) + h) + (setq h (/ m 60) m (- m (* h 60))) + (setq s2 (format "%02d:%02d" h m)))) + + (when (string-match (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$") + txt) ;; Tags are in the string - (if (or (eq org-agenda-remove-tags-when-in-prefix t) - (and org-agenda-remove-tags-when-in-prefix + (if (or (eq org-agenda-remove-tags t) + (and org-agenda-remove-tags org-prefix-has-tag)) (setq txt (replace-match "" t t txt)) (setq txt (replace-match @@ -14874,6 +22330,10 @@ only the correctly processes TXT should be returned - this is used by (match-string 2 txt)) t t txt)))) + (when remove-re + (while (string-match remove-re txt) + (setq txt (replace-match "" t t txt)))) + ;; Create the final string (if noprefix (setq rtn txt) @@ -14889,11 +22349,16 @@ only the correctly processes TXT should be returned - this is used by ;; And finally add the text properties (org-add-props rtn nil 'org-category (downcase category) 'tags tags + 'org-highest-priority org-highest-priority + 'org-lowest-priority org-lowest-priority 'prefix-length (- (length rtn) (length txt)) 'time-of-day time-of-day + 'txt txt + 'time time + 'extra extra 'dotime dotime)))) -(defvar org-agenda-sorting-strategy) +(defvar org-agenda-sorting-strategy) ;; because the def is in a let form (defvar org-agenda-sorting-strategy-selected nil) (defun org-agenda-add-time-grid-maybe (list ndays todayp) @@ -14979,11 +22444,8 @@ The optional STRING argument forces conversion into a 5 character wide string HH:MM." (save-match-data (when - (or - (string-match - "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)\\([AaPp][Mm]\\)?\\> *" s) - (string-match - "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\([AaPp][Mm]\\)\\> *" s)) + (or (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)\\([AaPp][Mm]\\)?\\> *" s) + (string-match "\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\([AaPp][Mm]\\)\\> *" s)) (let* ((h (string-to-number (match-string 1 s))) (m (if (match-end 3) (string-to-number (match-string 3 s)) 0)) (ampm (if (match-end 4) (downcase (match-string 4 s)))) @@ -15012,16 +22474,29 @@ HH:MM." (if (eq x 'line) (save-excursion (beginning-of-line 1) - (setq re (get-text-property (point) 'org-not-done-regexp)) + (setq re (get-text-property (point) 'org-todo-regexp)) (goto-char (+ (point) (or (get-text-property (point) 'prefix-length) 0))) - (and (looking-at (concat "[ \t]*\\.*" re)) - (add-text-properties (match-beginning 0) (match-end 0) - '(face org-todo)))) - (setq re (concat (get-text-property 0 'org-not-done-regexp x)) + (when (looking-at (concat "[ \t]*\\.*" re " +")) + (add-text-properties (match-beginning 0) (match-end 0) + (list 'face (org-get-todo-face 0))) + (let ((s (buffer-substring (match-beginning 1) (match-end 1)))) + (delete-region (match-beginning 1) (1- (match-end 0))) + (goto-char (match-beginning 1)) + (insert (format org-agenda-todo-keyword-format s))))) + (setq re (concat (get-text-property 0 'org-todo-regexp x)) pl (get-text-property 0 'prefix-length x)) - (and re (equal (string-match (concat "\\(\\.*\\)" re) x (or pl 0)) pl) - (add-text-properties (or (match-end 1) (match-end 0)) (match-end 0) - '(face org-todo) x)) + (when (and re + (equal (string-match (concat "\\(\\.*\\)" re "\\( +\\)") + x (or pl 0)) pl)) + (add-text-properties + (or (match-end 1) (match-end 0)) (match-end 0) + (list 'face (org-get-todo-face (match-string 2 x))) + x) + (setq x (concat (substring x 0 (match-end 1)) + (format org-agenda-todo-keyword-format + (match-string 2 x)) + " " + (substring x (match-end 3))))) x))) (defsubst org-cmp-priority (a b) @@ -15034,8 +22509,8 @@ HH:MM." (defsubst org-cmp-category (a b) "Compare the string values of categories of strings A and B." - (let ((ca (or (get-text-property 1 'category a) "")) - (cb (or (get-text-property 1 'category b) ""))) + (let ((ca (or (get-text-property 1 'org-category a) "")) + (cb (or (get-text-property 1 'org-category b) ""))) (cond ((string-lessp ca cb) -1) ((string-lessp cb ca) +1) (t nil)))) @@ -15076,6 +22551,85 @@ HH:MM." (eval (cons 'or org-agenda-sorting-strategy-selected)) '((-1 . t) (1 . nil) (nil . nil)))))) +;;; Agenda restriction lock + +(defvar org-agenda-restriction-lock-overlay (org-make-overlay 1 1) + "Overlay to mark the headline to which arenda commands are restricted.") +(org-overlay-put org-agenda-restriction-lock-overlay + 'face 'org-agenda-restriction-lock) +(org-overlay-put org-agenda-restriction-lock-overlay + 'help-echo "Agendas are currently limited to this subtree.") +(org-detach-overlay org-agenda-restriction-lock-overlay) +(defvar org-speedbar-restriction-lock-overlay (org-make-overlay 1 1) + "Overlay marking the agenda restriction line in speedbar.") +(org-overlay-put org-speedbar-restriction-lock-overlay + 'face 'org-agenda-restriction-lock) +(org-overlay-put org-speedbar-restriction-lock-overlay + 'help-echo "Agendas are currently limited to this item.") +(org-detach-overlay org-speedbar-restriction-lock-overlay) + +(defun org-agenda-set-restriction-lock (&optional type) + "Set restriction lock for agenda, to current subtree or file. +Restriction will be the file if TYPE is `file', or if type is the +universal prefix '(4), or if the cursor is before the first headline +in the file. Otherwise, restriction will be to the current subtree." + (interactive "P") + (and (equal type '(4)) (setq type 'file)) + (setq type (cond + (type type) + ((org-at-heading-p) 'subtree) + ((condition-case nil (org-back-to-heading t) (error nil)) + 'subtree) + (t 'file))) + (if (eq type 'subtree) + (progn + (setq org-agenda-restrict t) + (setq org-agenda-overriding-restriction 'subtree) + (put 'org-agenda-files 'org-restrict + (list (buffer-file-name (buffer-base-buffer)))) + (org-back-to-heading t) + (org-move-overlay org-agenda-restriction-lock-overlay (point) (point-at-eol)) + (move-marker org-agenda-restrict-begin (point)) + (move-marker org-agenda-restrict-end + (save-excursion (org-end-of-subtree t))) + (message "Locking agenda restriction to subtree")) + (put 'org-agenda-files 'org-restrict + (list (buffer-file-name (buffer-base-buffer)))) + (setq org-agenda-restrict nil) + (setq org-agenda-overriding-restriction 'file) + (move-marker org-agenda-restrict-begin nil) + (move-marker org-agenda-restrict-end nil) + (message "Locking agenda restriction to file")) + (setq current-prefix-arg nil) + (org-agenda-maybe-redo)) + +(defun org-agenda-remove-restriction-lock (&optional noupdate) + "Remove the agenda restriction lock." + (interactive "P") + (org-detach-overlay org-agenda-restriction-lock-overlay) + (org-detach-overlay org-speedbar-restriction-lock-overlay) + (setq org-agenda-overriding-restriction nil) + (setq org-agenda-restrict nil) + (put 'org-agenda-files 'org-restrict nil) + (move-marker org-agenda-restrict-begin nil) + (move-marker org-agenda-restrict-end nil) + (setq current-prefix-arg nil) + (message "Agenda restriction lock removed") + (or noupdate (org-agenda-maybe-redo))) + +(defun org-agenda-maybe-redo () + "If there is any window showing the agenda view, update it." + (let ((w (get-buffer-window org-agenda-buffer-name t)) + (w0 (selected-window))) + (when w + (select-window w) + (org-agenda-redo) + (select-window w0) + (if org-agenda-overriding-restriction + (message "Agenda view shifted to new %s restriction" + org-agenda-overriding-restriction) + (message "Agenda restriction lock removed"))))) + ;;; Agenda commands (defun org-agenda-check-type (error &rest types) @@ -15093,7 +22647,8 @@ If ERROR is non-nil, throw an error, otherwise just return nil." (let ((buf (current-buffer))) (if (not (one-window-p)) (delete-window)) (kill-buffer buf) - (org-agenda-maybe-reset-markers 'force)) + (org-agenda-reset-markers) + (org-columns-remove-overlays)) ;; Maybe restore the pre-agenda window configuration. (and org-agenda-restore-windows-after-quit (not (eq org-agenda-window-setup 'other-frame)) @@ -15109,6 +22664,13 @@ Org-mode buffers visited directly by the user will not be touched." (setq org-agenda-new-buffers nil) (org-agenda-quit)) +(defun org-agenda-execute (arg) + "Execute another agenda command, keeping same window.\\ +So this is just a shortcut for `\\[org-agenda]', available in the agenda." + (interactive "P") + (let ((org-agenda-window-setup 'current-window)) + (org-agenda arg))) + (defun org-save-all-org-buffers () "Save all Org-mode buffers without user confirmation." (interactive) @@ -15122,15 +22684,61 @@ When this is the global TODO list, a prefix argument will be interpreted." (interactive) (let* ((org-agenda-keep-modes t) (line (org-current-line)) - (window-line (- line (org-current-line (window-start))))) + (window-line (- line (org-current-line (window-start)))) + (lprops (get 'org-agenda-redo-command 'org-lprops))) (message "Rebuilding agenda buffer...") - (eval org-agenda-redo-command) + (org-let lprops '(eval org-agenda-redo-command)) (setq org-agenda-undo-list nil org-agenda-pending-undo-list nil) (message "Rebuilding agenda buffer...done") (goto-line line) (recenter window-line))) +(defun org-agenda-manipulate-query-add () + "Manipulate the query by adding a search term with positive selection. +Positive selection means, the term must be matched for selection of an entry." + (interactive) + (org-agenda-manipulate-query ?\[)) +(defun org-agenda-manipulate-query-subtract () + "Manipulate the query by adding a search term with negative selection. +Negative selection means, term must not be matched for selection of an entry." + (interactive) + (org-agenda-manipulate-query ?\])) +(defun org-agenda-manipulate-query-add-re () + "Manipulate the query by adding a search regexp with positive selection. +Positive selection means, the regexp must match for selection of an entry." + (interactive) + (org-agenda-manipulate-query ?\{)) +(defun org-agenda-manipulate-query-subtract-re () + "Manipulate the query by adding a search regexp with negative selection. +Negative selection means, regexp must not match for selection of an entry." + (interactive) + (org-agenda-manipulate-query ?\})) +(defun org-agenda-manipulate-query (char) + (cond + ((eq org-agenda-type 'search) + (org-add-to-string + 'org-agenda-query-string + (cdr (assoc char '((?\[ . " +") (?\] . " -") + (?\{ . " +{}") (?\} . " -{}"))))) + (setq org-agenda-redo-command + (list 'org-search-view + (+ (length org-agenda-query-string) + (if (member char '(?\{ ?\})) 0 1)) + org-agenda-query-string)) + (set-register org-agenda-query-register org-agenda-query-string) + (org-agenda-redo)) + (t (error "Canot manipulate query for %s-type agenda buffers" + org-agenda-type)))) + +(defun org-add-to-string (var string) + (set var (concat (symbol-value var) string))) + +(defun org-agenda-goto-date (date) + "Jump to DATE in agenda." + (interactive (list (org-read-date))) + (org-agenda-list nil date)) + (defun org-agenda-goto-today () "Go to today." (interactive) @@ -15139,77 +22747,131 @@ When this is the global TODO list, a prefix argument will be interpreted." (cond (tdpos (goto-char tdpos)) ((eq org-agenda-type 'agenda) - (let ((org-agenda-overriding-arguments org-agenda-last-arguments)) - (setf (nth 1 org-agenda-overriding-arguments) nil) + (let* ((sd (time-to-days + (time-subtract (current-time) + (list 0 (* 3600 org-extend-today-until) 0)))) + (comp (org-agenda-compute-time-span sd org-agenda-span)) + (org-agenda-overriding-arguments org-agenda-last-arguments)) + (setf (nth 1 org-agenda-overriding-arguments) (car comp)) + (setf (nth 2 org-agenda-overriding-arguments) (cdr comp)) (org-agenda-redo) - (org-agenda-find-today-or-agenda))) + (org-agenda-find-same-or-today-or-agenda))) (t (error "Cannot find today"))))) -(defun org-agenda-find-today-or-agenda () +(defun org-agenda-find-same-or-today-or-agenda (&optional cnt) (goto-char - (or (text-property-any (point-min) (point-max) 'org-today t) + (or (and cnt (text-property-any (point-min) (point-max) 'org-day-cnt cnt)) + (text-property-any (point-min) (point-max) 'org-today t) (text-property-any (point-min) (point-max) 'org-agenda-type 'agenda) (point-min)))) (defun org-agenda-later (arg) - "Go forward in time by `org-agenda-ndays' days. -With prefix ARG, go forward that many times `org-agenda-ndays'." + "Go forward in time by thee current span. +With prefix ARG, go forward that many times the current span." (interactive "p") (org-agenda-check-type t 'agenda) - (let ((org-agenda-overriding-arguments - (list (car org-agenda-last-arguments) - (+ org-starting-day (* arg org-agenda-ndays)) - nil t))) - (org-agenda-redo) - (org-agenda-find-today-or-agenda))) + (let* ((span org-agenda-span) + (sd org-starting-day) + (greg (calendar-gregorian-from-absolute sd)) + (cnt (get-text-property (point) 'org-day-cnt)) + greg2 nd) + (cond + ((eq span 'day) + (setq sd (+ arg sd) nd 1)) + ((eq span 'week) + (setq sd (+ (* 7 arg) sd) nd 7)) + ((eq span 'month) + (setq greg2 (list (+ (car greg) arg) (nth 1 greg) (nth 2 greg)) + sd (calendar-absolute-from-gregorian greg2)) + (setcar greg2 (1+ (car greg2))) + (setq nd (- (calendar-absolute-from-gregorian greg2) sd))) + ((eq span 'year) + (setq greg2 (list (car greg) (nth 1 greg) (+ arg (nth 2 greg))) + sd (calendar-absolute-from-gregorian greg2)) + (setcar (nthcdr 2 greg2) (1+ (nth 2 greg2))) + (setq nd (- (calendar-absolute-from-gregorian greg2) sd)))) + (let ((org-agenda-overriding-arguments + (list (car org-agenda-last-arguments) sd nd t))) + (org-agenda-redo) + (org-agenda-find-same-or-today-or-agenda cnt)))) (defun org-agenda-earlier (arg) - "Go back in time by `org-agenda-ndays' days. -With prefix ARG, go back that many times `org-agenda-ndays'." + "Go backward in time by the current span. +With prefix ARG, go backward that many times the current span." (interactive "p") - (org-agenda-check-type t 'agenda) - (let ((org-agenda-overriding-arguments - (list (car org-agenda-last-arguments) - (- org-starting-day (* arg org-agenda-ndays)) - nil t))) - (org-agenda-redo) - (org-agenda-find-today-or-agenda))) - -(defun org-agenda-week-view () - "Switch to weekly view for agenda." - (interactive) - (org-agenda-check-type t 'agenda) - (if (= org-agenda-ndays 7) - (error "This is already the week view")) - (setq org-agenda-ndays 7) - (let ((org-agenda-overriding-arguments - (list (car org-agenda-last-arguments) - (or (get-text-property (point) 'day) - org-starting-day) - nil t))) - (org-agenda-redo) - (org-agenda-find-today-or-agenda)) - (org-agenda-set-mode-name) - (message "Switched to week view")) + (org-agenda-later (- arg))) (defun org-agenda-day-view () "Switch to daily view for agenda." (interactive) - (org-agenda-check-type t 'agenda) - (if (= org-agenda-ndays 1) - (error "This is already the day view")) (setq org-agenda-ndays 1) - (let ((org-agenda-overriding-arguments - (list (car org-agenda-last-arguments) - (or (get-text-property (point) 'day) - org-starting-day) - nil t))) - (org-agenda-redo) - (org-agenda-find-today-or-agenda)) - (org-agenda-set-mode-name) - (message "Switched to day view")) + (org-agenda-change-time-span 'day)) +(defun org-agenda-week-view () + "Switch to daily view for agenda." + (interactive) + (setq org-agenda-ndays 7) + (org-agenda-change-time-span 'week)) +(defun org-agenda-month-view () + "Switch to daily view for agenda." + (interactive) + (org-agenda-change-time-span 'month)) +(defun org-agenda-year-view () + "Switch to daily view for agenda." + (interactive) + (if (y-or-n-p "Are you sure you want to compute the agenda for an entire year? ") + (org-agenda-change-time-span 'year) + (error "Abort"))) -;; FIXME: this no longer works if user make date format that starts with a blank +(defun org-agenda-change-time-span (span) + "Change the agenda view to SPAN. +SPAN may be `day', `week', `month', `year'." + (org-agenda-check-type t 'agenda) + (if (equal org-agenda-span span) + (error "Viewing span is already \"%s\"" span)) + (let* ((sd (or (get-text-property (point) 'day) + org-starting-day)) + (computed (org-agenda-compute-time-span sd span)) + (org-agenda-overriding-arguments + (list (car org-agenda-last-arguments) + (car computed) (cdr computed) t))) + (org-agenda-redo) + (org-agenda-find-same-or-today-or-agenda)) + (org-agenda-set-mode-name) + (message "Switched to %s view" span)) + +(defun org-agenda-compute-time-span (sd span) + "Compute starting date and number of days for agenda. +SPAN may be `day', `week', `month', `year'. The return value +is a cons cell with the starting date and the number of days, +so that the date SD will be in that range." + (let* ((greg (calendar-gregorian-from-absolute sd)) + nd) + (cond + ((eq span 'day) + (setq nd 1)) + ((eq span 'week) + (let* ((nt (calendar-day-of-week + (calendar-gregorian-from-absolute sd))) + (d (if org-agenda-start-on-weekday + (- nt org-agenda-start-on-weekday) + 0))) + (setq sd (- sd (+ (if (< d 0) 7 0) d))) + (setq nd 7))) + ((eq span 'month) + (setq sd (calendar-absolute-from-gregorian + (list (car greg) 1 (nth 2 greg))) + nd (- (calendar-absolute-from-gregorian + (list (1+ (car greg)) 1 (nth 2 greg))) + sd))) + ((eq span 'year) + (setq sd (calendar-absolute-from-gregorian + (list 1 1 (nth 2 greg))) + nd (- (calendar-absolute-from-gregorian + (list 1 1 (1+ (nth 2 greg)))) + sd)))) + (cons sd nd))) + +;; FIXME: does not work if user makes date format that starts with a blank (defun org-agenda-next-date-line (&optional arg) "Jump to the next line indicating a date in agenda buffer." (interactive "p") @@ -15243,10 +22905,10 @@ With prefix ARG, go back that many times `org-agenda-ndays'." "Detach overlay INDEX." (funcall (if (featurep 'xemacs) 'detach-extent 'delete-overlay) org-hl)) +;; FIXME this is currently not used. (defun org-highlight-until-next-command (beg end &optional buffer) (org-highlight beg end buffer) (add-hook 'pre-command-hook 'org-unhighlight-once)) - (defun org-unhighlight-once () (remove-hook 'pre-command-hook 'org-unhighlight-once) (org-unhighlight)) @@ -15340,8 +23002,14 @@ and by additional input from the age of a schedules or deadline entry." (save-excursion (and (outline-next-heading) (org-flag-heading nil)))) ; show the next heading + (recenter (/ (window-height) 2)) + (run-hooks 'org-agenda-after-show-hook) (and highlight (org-highlight (point-at-bol) (point-at-eol))))) +(defvar org-agenda-after-show-hook nil + "Normal hook run after an item has been shown from the agenda. +Point is in the buffer where the item originated.") + (defun org-agenda-kill () "Kill the entry or subtree belonging to the current agenda entry." (interactive) @@ -15350,14 +23018,15 @@ and by additional input from the age of a schedules or deadline entry." (org-agenda-error))) (buffer (marker-buffer marker)) (pos (marker-position marker)) + (type (get-text-property (point) 'type)) dbeg dend (n 0) conf) (org-with-remote-undo buffer (with-current-buffer buffer (save-excursion (goto-char pos) - (if (org-mode-p) + (if (and (org-mode-p) (not (member type '("sexp")))) (setq dbeg (progn (org-back-to-heading t) (point)) - dend (org-end-of-subtree t)) + dend (org-end-of-subtree t t)) (setq dbeg (point-at-bol) dend (min (point-max) (1+ (point-at-eol))))) (goto-char dbeg) @@ -15413,20 +23082,25 @@ If this information is not given, the function uses the tree at point." (setq p (marker-position m)) (>= p beg) (<= p end)) - (let (buffer-read-only) + (let ((inhibit-read-only t)) (delete-region (point-at-bol) (1+ (point-at-eol))))) (beginning-of-line 0)))))) (defun org-agenda-open-link () "Follow the link in the current line, if any." (interactive) - (let ((eol (point-at-eol))) - (save-excursion - (if (or (re-search-forward org-bracket-link-regexp eol t) - (re-search-forward org-angle-link-re eol t) - (re-search-forward org-plain-link-re eol t)) - (call-interactively 'org-open-at-point) - (error "No link in current line"))))) + (org-agenda-copy-local-variable 'org-link-abbrev-alist-local) + (save-excursion + (save-restriction + (narrow-to-region (point-at-bol) (point-at-eol)) + (org-open-at-point)))) + +(defun org-agenda-copy-local-variable (var) + "Get a variable from a referenced buffer and install it here." + (let ((m (get-text-property (point) 'org-marker))) + (when (and m (buffer-live-p (marker-buffer m))) + (org-set-local var (with-current-buffer (marker-buffer m) + (symbol-value var)))))) (defun org-agenda-switch-to (&optional delete-other-windows) "Go to the Org-mode file which contains the item at point." @@ -15502,6 +23176,16 @@ dedicated frame)." "Marker pointing to the headline that last changed its TODO state by a remote command from the agenda.") +(defun org-agenda-todo-nextset () + "Switch TODO entry to next sequence." + (interactive) + (org-agenda-todo 'nextset)) + +(defun org-agenda-todo-previousset () + "Switch TODO entry to previous sequence." + (interactive) + (org-agenda-todo 'previousset)) + (defun org-agenda-todo (&optional arg) "Cycle TODO state of line at point, also in Org-mode file. This changes the line at point, all other lines in the agenda referring to @@ -15514,7 +23198,7 @@ the same tree node, and the headline of the tree node in the Org-mode file." (buffer (marker-buffer marker)) (pos (marker-position marker)) (hdmarker (get-text-property (point) 'org-hd-marker)) - (buffer-read-only nil) + (inhibit-read-only t) newhead) (org-with-remote-undo buffer (with-current-buffer buffer @@ -15542,7 +23226,7 @@ The new content of the line will be NEWHEAD (as modified by `equal' against all `org-hd-marker' text properties in the file. If FIXFACE is non-nil, the face of each item is modified acording to the new TODO state." - (let* ((buffer-read-only nil) + (let* ((inhibit-read-only t) props m pl undone-face done-face finish new dotime cat tags) (save-excursion (goto-char (point-max)) @@ -15580,20 +23264,25 @@ the new TODO state." (beginning-of-line 0))) (org-finalize-agenda))) -;; FIXME: allow negative value for org-agenda-align-tags-to-column -;; See the code in set-tags for the way to do this. (defun org-agenda-align-tags (&optional line) - "Align all tags in agenda items to `org-agenda-align-tags-to-column'." - (let ((buffer-read-only)) + "Align all tags in agenda items to `org-agenda-tags-column'." + (let ((inhibit-read-only t) l c) (save-excursion (goto-char (if line (point-at-bol) (point-min))) - (while (re-search-forward "\\([ \t]+\\):[a-zA-Z0-9_@:]+:[ \t]*$" + (while (re-search-forward (org-re "\\([ \t]+\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$") (if line (point-at-eol) nil) t) + (add-text-properties + (match-beginning 2) (match-end 2) + (list 'face (delq nil (list 'org-tag (get-text-property + (match-beginning 2) 'face))))) + (setq l (- (match-end 2) (match-beginning 2)) + c (if (< org-agenda-tags-column 0) + (- (abs org-agenda-tags-column) l) + org-agenda-tags-column)) (delete-region (match-beginning 1) (match-end 1)) (goto-char (match-beginning 1)) (insert (org-add-props - (make-string (max 1 (- org-agenda-align-tags-to-column - (current-column))) ?\ ) + (make-string (max 1 (- c (current-column))) ?\ ) (text-properties-at (point)))))))) (defun org-agenda-priority-up () @@ -15614,10 +23303,10 @@ the same tree node, and the headline of the tree node in the Org-mode file." (org-agenda-check-no-diary) (let* ((marker (or (get-text-property (point) 'org-marker) (org-agenda-error))) - (buffer (marker-buffer marker)) - (pos (marker-position marker)) (hdmarker (get-text-property (point) 'org-hd-marker)) - (buffer-read-only nil) + (buffer (marker-buffer hdmarker)) + (pos (marker-position hdmarker)) + (inhibit-read-only t) newhead) (org-with-remote-undo buffer (with-current-buffer buffer @@ -15639,21 +23328,23 @@ POS defaults to point. If tags are inherited, the list contains the targets in the same sequence as the headlines appear, i.e. the tags of the current headline come last." (interactive) - (let (tags) + (let (tags lastpos) (save-excursion (save-restriction (widen) (goto-char (or pos (point))) (save-match-data - (org-back-to-heading t) (condition-case nil - (while t - (if (looking-at "[^\r\n]+?:\\([a-zA-Z_@0-9:]+\\):[ \t]*\\([\n\r]\\|\\'\\)") - (setq tags (append (org-split-string - (org-match-string-no-properties 1) ":") - tags))) - (or org-use-tag-inheritance (error "")) - (org-up-heading-all 1)) + (progn + (org-back-to-heading t) + (while (not (equal lastpos (point))) + (setq lastpos (point)) + (if (looking-at (org-re "[^\r\n]+?:\\([[:alnum:]_@:]+\\):[ \t]*$")) + (setq tags (append (org-split-string + (org-match-string-no-properties 1) ":") + tags))) + (or org-use-tag-inheritance (error "")) + (org-up-heading-all 1))) (error nil)))) tags))) @@ -15662,26 +23353,30 @@ the tags of the current headline come last." "Set tags for the current headline." (interactive) (org-agenda-check-no-diary) - (org-agenda-show) ;;; FIXME This is a stupid hack and should not be needed - (let* ((hdmarker (or (get-text-property (point) 'org-hd-marker) - (org-agenda-error))) - (buffer (marker-buffer hdmarker)) - (pos (marker-position hdmarker)) - (buffer-read-only nil) - newhead) - (org-with-remote-undo buffer - (with-current-buffer buffer - (widen) - (goto-char pos) - (org-show-context 'agenda) - (save-excursion - (and (outline-next-heading) - (org-flag-heading nil))) ; show the next heading - (call-interactively 'org-set-tags) - (end-of-line 1) - (setq newhead (org-get-heading))) - (org-agenda-change-all-lines newhead hdmarker) - (beginning-of-line 1)))) + (if (and (org-region-active-p) (interactive-p)) + (call-interactively 'org-change-tag-in-region) + (org-agenda-show) ;;; FIXME This is a stupid hack and should not be needed + (let* ((hdmarker (or (get-text-property (point) 'org-hd-marker) + (org-agenda-error))) + (buffer (marker-buffer hdmarker)) + (pos (marker-position hdmarker)) + (inhibit-read-only t) + newhead) + (org-with-remote-undo buffer + (with-current-buffer buffer + (widen) + (goto-char pos) + (save-excursion + (org-show-context 'agenda)) + (save-excursion + (and (outline-next-heading) + (org-flag-heading nil))) ; show the next heading + (goto-char pos) + (call-interactively 'org-set-tags) + (end-of-line 1) + (setq newhead (org-get-heading))) + (org-agenda-change-all-lines newhead hdmarker) + (beginning-of-line 1))))) (defun org-agenda-toggle-archive-tag () "Toggle the archive tag for the current entry." @@ -15692,7 +23387,7 @@ the tags of the current headline come last." (org-agenda-error))) (buffer (marker-buffer hdmarker)) (pos (marker-position hdmarker)) - (buffer-read-only nil) + (inhibit-read-only t) newhead) (org-with-remote-undo buffer (with-current-buffer buffer @@ -15732,11 +23427,11 @@ the tags of the current headline come last." (interactive "p") (org-agenda-date-later (- arg) what)) -(defun org-agenda-show-new-time (marker stamp) +(defun org-agenda-show-new-time (marker stamp &optional prefix) "Show new date stamp via text properties." ;; We use text properties to make this undoable - (let ((buffer-read-only nil)) - (setq stamp (concat " => " stamp)) + (let ((inhibit-read-only t)) + (setq stamp (concat " " prefix " => " stamp)) (save-excursion (goto-char (point-max)) (while (not (bobp)) @@ -15784,16 +23479,20 @@ be used to request time specification in the time stamp." (org-agenda-check-no-diary) (let* ((marker (or (get-text-property (point) 'org-marker) (org-agenda-error))) + (type (marker-insertion-type marker)) (buffer (marker-buffer marker)) (pos (marker-position marker)) (org-insert-labeled-timestamps-at-point nil) ts) + (when type (message "%s" type) (sit-for 3)) + (set-marker-insertion-type marker t) (org-with-remote-undo buffer (with-current-buffer buffer (widen) (goto-char pos) - (setq ts (org-schedule)) - (message "Item scheduled for %s" ts))))) + (setq ts (org-schedule arg))) + (org-agenda-show-new-time marker ts "S")) + (message "Item scheduled for %s" ts))) (defun org-agenda-deadline (arg) "Schedule the item at point." @@ -15810,14 +23509,19 @@ be used to request time specification in the time stamp." (with-current-buffer buffer (widen) (goto-char pos) - (setq ts (org-deadline)) - (message "Deadline for this item set to %s" ts))))) + (setq ts (org-deadline arg))) + (org-agenda-show-new-time marker ts "S")) + (message "Deadline for this item set to %s" ts))) -(defun org-get-heading () +(defun org-get-heading (&optional no-tags) "Return the heading of the current entry, without the stars." (save-excursion (org-back-to-heading t) - (if (looking-at "\\*+[ \t]+\\([^\r\n]*\\)") (match-string 1) ""))) + (if (looking-at + (if no-tags + (org-re "\\*+[ \t]+\\([^\n\r]*?\\)\\([ \t]+:[[:alnum:]:_@]+:[ \t]*\\)?$") + "\\*+[ \t]+\\([^\r\n]*\\)")) + (match-string 1) ""))) (defun org-agenda-clock-in (&optional arg) "Start the clock on the currently selected item." @@ -15902,10 +23606,9 @@ the cursor position." (point (point)) (date (calendar-gregorian-from-absolute (get-text-property point 'day))) - ;; the following 3 vars are needed in the calendar - (displayed-day (extract-calendar-day date)) - (displayed-month (extract-calendar-month date)) - (displayed-year (extract-calendar-year date))) + ;; the following 2 vars are needed in the calendar + (displayed-month (car date)) + (displayed-year (nth 2 date))) (unwind-protect (progn (fset 'calendar-cursor-to-date @@ -15925,12 +23628,17 @@ the cursor position." (interactive) (org-agenda-execute-calendar-command 'list-calendar-holidays)) +(defvar calendar-longitude) +(defvar calendar-latitude) +(defvar calendar-location-name) + (defun org-agenda-sunrise-sunset (arg) "Display sunrise and sunset for the cursor date. Latitude and longitude can be specified with the variables `calendar-latitude' and `calendar-longitude'. When called with prefix argument, latitude and longitude will be prompted for." (interactive "P") + (require 'solar) (let ((calendar-longitude (if arg nil calendar-longitude)) (calendar-latitude (if arg nil calendar-latitude)) (calendar-location-name @@ -15945,7 +23653,9 @@ argument, latitude and longitude will be prompted for." (error "Don't know which date to open in calendar"))) (date (calendar-gregorian-from-absolute day)) (calendar-move-hook nil) + (calendar-view-holidays-initially-flag nil) (view-calendar-holidays-initially nil) + (calendar-view-diary-initially-flag nil) (view-diary-entries-initially nil)) (calendar) (calendar-goto-date date))) @@ -15976,6 +23686,7 @@ This is a command that has to be installed in `calendar-mode-map'." "Hebrew: " (calendar-hebrew-date-string date) " (until sunset)\n" "Islamic: " (calendar-islamic-date-string date) " (until sunset)\n" "French: " (calendar-french-date-string date) "\n" + "Baha'i: " (calendar-bahai-date-string date) " (until sunset)\n" "Mayan: " (calendar-mayan-date-string date) "\n" "Coptic: " (calendar-coptic-date-string date) "\n" "Ethiopic: " (calendar-ethiopic-date-string date) "\n" @@ -15992,11 +23703,11 @@ This is a command that has to be installed in `calendar-mode-map'." (defvar org-cdlatex-mode-map (make-sparse-keymap) "Keymap for the minor `org-cdlatex-mode'.") -(define-key org-cdlatex-mode-map "_" 'org-cdlatex-underscore-caret) -(define-key org-cdlatex-mode-map "^" 'org-cdlatex-underscore-caret) -(define-key org-cdlatex-mode-map "`" 'cdlatex-math-symbol) -(define-key org-cdlatex-mode-map "'" 'org-cdlatex-math-modify) -(define-key org-cdlatex-mode-map "\C-c{" 'cdlatex-environment) +(org-defkey org-cdlatex-mode-map "_" 'org-cdlatex-underscore-caret) +(org-defkey org-cdlatex-mode-map "^" 'org-cdlatex-underscore-caret) +(org-defkey org-cdlatex-mode-map "`" 'cdlatex-math-symbol) +(org-defkey org-cdlatex-mode-map "'" 'org-cdlatex-math-modify) +(org-defkey org-cdlatex-mode-map "\C-c{" 'cdlatex-environment) (defvar org-cdlatex-texmathp-advice-is-done nil "Flag remembering if we have applied the advice to texmathp already.") @@ -16064,7 +23775,7 @@ looks only before point, not after." (while (string-match re str start) (cond ((= (match-end 0) (length str)) - (throw 'exit (cons "$" (+ lim (match-beginning 0))))) + (throw 'exit (cons "$" (+ lim (match-beginning 0) 1)))) ((= (match-end 0) (- (length str) 5)) (throw 'exit nil)) (t (setq start (match-end 0)))))) @@ -16156,11 +23867,12 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." "Creating images for entry...%s")))) (message msg "") (narrow-to-region beg end) + (goto-char beg) (org-format-latex (concat "ltxpng/" (file-name-sans-extension (file-name-nondirectory buffer-file-name))) - default-directory 'overlays msg at) + default-directory 'overlays msg at 'forbuffer) (message msg "done. Use `C-c C-c' to remove images."))))) (defvar org-latex-regexps @@ -16173,7 +23885,7 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." ("$$" "\\$\\$[^\000]*?\\$\\$" 0 t)) "Regular expressions for matching embedded LaTeX.") -(defun org-format-latex (prefix &optional dir overlays msg at) +(defun org-format-latex (prefix &optional dir overlays msg at forbuffer) "Replace LaTeX fragments with links to an image, and produce images." (if (and overlays (fboundp 'clear-image-cache)) (clear-image-cache)) (let* ((prefixnodir (file-name-nondirectory prefix)) @@ -16210,7 +23922,7 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." (setq checkdir t) (or (file-directory-p todir) (make-directory todir))) (org-create-formula-image - txt movefile opt) + txt movefile opt forbuffer) (if overlays (progn (setq ov (org-make-overlay beg end)) @@ -16229,31 +23941,27 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." (insert link)))))))) ;; This function borrows from Ganesh Swami's latex2png.el -(defun org-create-formula-image (string tofile options) +(defun org-create-formula-image (string tofile options buffer) (let* ((tmpdir (if (featurep 'xemacs) (temp-directory) temporary-file-directory)) (texfilebase (make-temp-name (expand-file-name "orgtex" tmpdir))) - -;(texfilebase (make-temp-file "orgtex")) -; (dummy (delete-file texfilebase)) (texfile (concat texfilebase ".tex")) (dvifile (concat texfilebase ".dvi")) (pngfile (concat texfilebase ".png")) - (scale (number-to-string (* 1000 (or (plist-get options :scale) 1.0)))) - (fg (or (plist-get options :foreground) "Black")) - (bg (or (plist-get options :background) "Transparent"))) + (fnh (face-attribute 'default :height nil)) + (scale (or (plist-get options (if buffer :scale :html-scale)) 1.0)) + (dpi (number-to-string (* scale (floor (* 0.9 (if buffer fnh 140.)))))) + (fg (or (plist-get options (if buffer :foreground :html-foreground)) + "Black")) + (bg (or (plist-get options (if buffer :background :html-background)) + "Transparent"))) + (if (eq fg 'default) (setq fg (org-dvipng-color :foreground))) + (if (eq bg 'default) (setq bg (org-dvipng-color :background))) (with-temp-file texfile - (insert "\\documentclass{article} -\\usepackage{fullpage} -\\usepackage{amssymb} -\\usepackage[usenames]{color} -\\usepackage{amsmath} -\\usepackage{latexsym} -\\usepackage[mathscr]{eucal} -\\pagestyle{empty} -\\begin{document}\n" string "\n\\end{document}\n")) + (insert org-format-latex-header + "\n\\begin{document}\n" string "\n\\end{document}\n")) (let ((dir default-directory)) (condition-case nil (progn @@ -16265,7 +23973,9 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." (progn (message "Failed to create dvi file from %s" texfile) nil) (call-process "dvipng" nil nil nil "-E" "-fg" fg "-bg" bg - "-x" scale "-y" scale "-T" "tight" + "-D" dpi + ;;"-x" scale "-y" scale + "-T" "tight" "-o" pngfile dvifile) (if (not (file-exists-p pngfile)) @@ -16276,6 +23986,16 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." (delete-file (concat texfilebase e))) pngfile)))) +(defun org-dvipng-color (attr) + "Return an rgb color specification for dvipng." + (apply 'format "rgb %s %s %s" + (mapcar 'org-normalize-color + (color-values (face-attribute 'default attr nil))))) + +(defun org-normalize-color (value) + "Return string to be used as color value for an RGB component." + (format "%g" (/ value 65535.0))) + ;;;; Exporting ;;; Variables, constants, and parameter plists @@ -16300,18 +24020,29 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." (:headline-levels . org-export-headline-levels) (:section-numbers . org-export-with-section-numbers) (:table-of-contents . org-export-with-toc) + (:preserve-breaks . org-export-preserve-breaks) (:archived-trees . org-export-with-archived-trees) (:emphasize . org-export-with-emphasize) (:sub-superscript . org-export-with-sub-superscripts) + (:special-strings . org-export-with-special-strings) + (:footnotes . org-export-with-footnotes) + (:drawers . org-export-with-drawers) + (:tags . org-export-with-tags) (:TeX-macros . org-export-with-TeX-macros) (:LaTeX-fragments . org-export-with-LaTeX-fragments) + (:skip-before-1st-heading . org-export-skip-text-before-1st-heading) (:fixed-width . org-export-with-fixed-width) (:timestamps . org-export-with-timestamps) + (:author-info . org-export-author-info) + (:time-stamp-file . org-export-time-stamp-file) (:tables . org-export-with-tables) (:table-auto-headline . org-export-highlight-first-table-line) (:style . org-export-html-style) + (:agenda-style . org-agenda-export-html-style) (:convert-org-links . org-export-html-link-org-files-as-html) (:inline-images . org-export-html-inline-images) + (:html-extension . org-export-html-extension) + (:html-table-tag . org-export-html-table-tag) (:expand-quoted-html . org-export-html-expand) (:timestamp . org-export-html-with-timestamp) (:publishing-directory . org-export-publishing-directory) @@ -16332,43 +24063,53 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." (defun org-infile-export-plist () "Return the property list with file-local settings for export." (save-excursion - (goto-char 0) - (let ((re (org-make-options-regexp - '("TITLE" "AUTHOR" "EMAIL" "TEXT" "OPTIONS" "LANGUAGE"))) - p key val text options) - (while (re-search-forward re nil t) - (setq key (org-match-string-no-properties 1) - val (org-match-string-no-properties 2)) - (cond - ((string-equal key "TITLE") (setq p (plist-put p :title val))) - ((string-equal key "AUTHOR")(setq p (plist-put p :author val))) - ((string-equal key "EMAIL") (setq p (plist-put p :email val))) - ((string-equal key "LANGUAGE") (setq p (plist-put p :language val))) - ((string-equal key "TEXT") - (setq text (if text (concat text "\n" val) val))) - ((string-equal key "OPTIONS") (setq options val)))) - (setq p (plist-put p :text text)) - (when options - (let ((op '(("H" . :headline-levels) - ("num" . :section-numbers) - ("toc" . :table-of-contents) - ("\\n" . :preserve-breaks) - ("@" . :expand-quoted-html) - (":" . :fixed-width) - ("|" . :tables) - ("^" . :sub-superscript) - ("*" . :emphasize) - ("TeX" . :TeX-macros) - ("LaTeX" . :LaTeX-fragments))) - o) - (while (setq o (pop op)) - (if (string-match (concat (regexp-quote (car o)) - ":\\([^ \t\n\r;,.]*\\)") - options) - (setq p (plist-put p (cdr o) - (car (read-from-string - (match-string 1 options))))))))) - p))) + (save-restriction + (widen) + (goto-char 0) + (let ((re (org-make-options-regexp + '("TITLE" "AUTHOR" "DATE" "EMAIL" "TEXT" "OPTIONS" "LANGUAGE"))) + p key val text options) + (while (re-search-forward re nil t) + (setq key (org-match-string-no-properties 1) + val (org-match-string-no-properties 2)) + (cond + ((string-equal key "TITLE") (setq p (plist-put p :title val))) + ((string-equal key "AUTHOR")(setq p (plist-put p :author val))) + ((string-equal key "EMAIL") (setq p (plist-put p :email val))) + ((string-equal key "DATE") (setq p (plist-put p :date val))) + ((string-equal key "LANGUAGE") (setq p (plist-put p :language val))) + ((string-equal key "TEXT") + (setq text (if text (concat text "\n" val) val))) + ((string-equal key "OPTIONS") (setq options val)))) + (setq p (plist-put p :text text)) + (when options + (let ((op '(("H" . :headline-levels) + ("num" . :section-numbers) + ("toc" . :table-of-contents) + ("\\n" . :preserve-breaks) + ("@" . :expand-quoted-html) + (":" . :fixed-width) + ("|" . :tables) + ("^" . :sub-superscript) + ("-" . :special-strings) + ("f" . :footnotes) + ("d" . :drawers) + ("tags" . :tags) + ("*" . :emphasize) + ("TeX" . :TeX-macros) + ("LaTeX" . :LaTeX-fragments) + ("skip" . :skip-before-1st-heading) + ("author" . :author-info) + ("timestamp" . :time-stamp-file))) + o) + (while (setq o (pop op)) + (if (string-match (concat (regexp-quote (car o)) + ":\\([^ \t\n\r;,.]*\\)") + options) + (setq p (plist-put p (cdr o) + (car (read-from-string + (match-string 1 options))))))))) + p)))) (defun org-export-directory (type plist) (let* ((val (plist-get plist :publishing-directory)) @@ -16377,19 +24118,11 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." val))) dir)) -(defun org-export-find-first-heading-line (list) - "Remove all lines from LIST which are before the first headline." - (let ((orig-list list) - (re (concat "^" outline-regexp))) - (while (and list - (not (string-match re (car list)))) - (pop list)) - (or list orig-list))) - (defun org-skip-comments (lines) "Skip lines starting with \"#\" and subtrees starting with COMMENT." (let ((re1 (concat "^\\(\\*+\\)[ \t]+" org-comment-string)) (re2 "^\\(\\*+\\)[ \t\n\r]") + (case-fold-search nil) rtn line level) (while (setq line (pop lines)) (cond @@ -16419,10 +24152,16 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." \[v] limit export to visible part of outline tree \[a] export as ASCII + \[h] export as HTML +\[H] export as HTML to temporary buffer +\[R] export region as HTML \[b] export as HTML and browse immediately \[x] export as XOXO +\[l] export as LaTeX +\[L] export as LaTeX to temporary buffer + \[i] export current file as iCalendar file \[I] export all agenda files as iCalendar files \[c] export agenda files into combined iCalendar file @@ -16437,7 +24176,11 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." (?a . org-export-as-ascii) (?h . org-export-as-html) (?b . org-export-as-html-and-open) + (?H . org-export-as-html-to-buffer) + (?R . org-export-region-as-html) (?x . org-export-as-xoxo) + (?l . org-export-as-latex) + (?L . org-export-as-latex-to-buffer) (?i . org-export-icalendar-this-file) (?I . org-export-icalendar-all-agenda-files) (?c . org-export-icalendar-combine-agenda-files) @@ -16465,6 +24208,7 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." ("curren") ("yen") ("brvbar") + ("vert" . "|") ("sect") ("uml") ("copy") @@ -16648,8 +24392,8 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." ("prop") ("proptp"."∝") ("infin") ("infty"."∞") ("ang") ("angle"."∠") - ("and") ("vee"."∧") - ("or") ("wedge"."∨") + ("and") ("wedge"."∧") + ("or") ("vee"."∨") ("cap") ("cup") ("int") @@ -16681,6 +24425,7 @@ The images can be removed again with \\[org-ctrl-c-ctrl-c]." ("clubs") ("clubsuit"."♣") ("hearts") ("diamondsuit"."♥") ("diams") ("diamondsuit"."♦") + ("smile"."☺") ("blacksmile"."☻") ("sad"."☹") ("quot") ("amp") ("lt") @@ -16758,7 +24503,7 @@ translations. There is currently no way for users to extend this.") ;;; General functions for all backends (defun org-cleaned-string-for-export (string &rest parameters) - "Cleanup a buffer substring so that links can be created safely." + "Cleanup a buffer STRING so that links can be created safely." (interactive) (let* ((re-radio (and org-target-link-regexp (concat "\\([^<]\\)\\(" org-target-link-regexp "\\)"))) @@ -16766,52 +24511,64 @@ translations. There is currently no way for users to extend this.") (re-angle-link (concat "\\([^[]\\)" org-angle-link-re)) (re-archive (concat ":" org-archive-tag ":")) (re-quote (concat "^\\*+[ \t]+" org-quote-string "\\>")) - (htmlp (memq :for-html parameters)) - (outline-regexp "\\*+") - rtn) - (save-excursion - (set-buffer (get-buffer-create " org-mode-tmp")) + (re-commented (concat "^\\*+[ \t]+" org-comment-string "\\>")) + (htmlp (plist-get parameters :for-html)) + (asciip (plist-get parameters :for-ascii)) + (latexp (plist-get parameters :for-LaTeX)) + (commentsp (plist-get parameters :comments)) + (archived-trees (plist-get parameters :archived-trees)) + (inhibit-read-only t) + (drawers org-drawers) + (exp-drawers (plist-get parameters :drawers)) + (outline-regexp "\\*+ ") + a b xx + rtn p) + (with-current-buffer (get-buffer-create " org-mode-tmp") (erase-buffer) (insert string) + ;; Remove license-to-kill stuff + (while (setq p (text-property-any (point-min) (point-max) + :org-license-to-kill t)) + (delete-region p (next-single-property-change p :org-license-to-kill))) + (let ((org-inhibit-startup t)) (org-mode)) (untabify (point-min) (point-max)) + ;; Get rid of drawers + (unless (eq t exp-drawers) + (goto-char (point-min)) + (let ((re (concat "^[ \t]*:\\(" + (mapconcat + 'identity + (org-delete-all exp-drawers + (copy-sequence drawers)) + "\\|") + "\\):[ \t]*\n\\([^@]*?\n\\)?[ \t]*:END:[ \t]*\n"))) + (while (re-search-forward re nil t) + (replace-match "")))) + + ;; Get the correct stuff before the first headline + (when (plist-get parameters :skip-before-1st-heading) + (goto-char (point-min)) + (when (re-search-forward "^\\*+[ \t]" nil t) + (delete-region (point-min) (match-beginning 0)) + (goto-char (point-min)) + (insert "\n"))) + (when (plist-get parameters :add-text) + (goto-char (point-min)) + (insert (plist-get parameters :add-text) "\n")) + ;; Get rid of archived trees - (when (not (eq org-export-with-archived-trees t)) + (when (not (eq archived-trees t)) (goto-char (point-min)) (while (re-search-forward re-archive nil t) - (if (not (org-on-heading-p)) + (if (not (org-on-heading-p t)) (org-end-of-subtree t) (beginning-of-line 1) - (delete-region - (if org-export-with-archived-trees (1+ (point-at-eol)) (point)) - (org-end-of-subtree t))))) - - ;; Protect stuff from HTML processing - (goto-char (point-min)) - (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t) - (add-text-properties (match-beginning 0) (match-end 0) - '(org-protected t))) - (when htmlp - (goto-char (point-min)) - (while (re-search-forward "^#\\+HTML:[ \t]*\\(.*\\)" nil t) - (replace-match "\\1" t) - (add-text-properties - (point-at-bol) (min (1+ (point-at-eol)) (point-max)) - '(org-protected t)))) - (goto-char (point-min)) - (while (re-search-forward - "^#\\+BEGIN_HTML\\>.*\\(\n.*\\)*?\n#\\+END_HTML\\>.*\n?" nil t) - (if htmlp - (add-text-properties (match-beginning 1) (1+ (match-end 1)) - '(org-protected t)) - (delete-region (match-beginning 0) (match-end 0)))) - (goto-char (point-min)) - (while (re-search-forward re-quote nil t) - (goto-char (match-beginning 0)) - (end-of-line 1) - (add-text-properties (point) (org-end-of-subtree t) - '(org-protected t))) + (setq a (if archived-trees + (1+ (point-at-eol)) (point)) + b (org-end-of-subtree t)) + (if (> b a) (delete-region a b))))) ;; Find targets in comments and move them out of comments, ;; but mark them as targets that should be invisible @@ -16819,10 +24576,102 @@ translations. There is currently no way for users to extend this.") (while (re-search-forward "^#.*?\\(<<\r\n]+>>>?\\).*" nil t) (replace-match "\\1(INVISIBLE)")) - ;; Remove comments + ;; Protect backend specific stuff, throw away the others. + (let ((formatters + `((,htmlp "HTML" "BEGIN_HTML" "END_HTML") + (,asciip "ASCII" "BEGIN_ASCII" "END_ASCII") + (,latexp "LaTeX" "BEGIN_LaTeX" "END_LaTeX"))) + fmt) + (goto-char (point-min)) + (while (re-search-forward "^#\\+BEGIN_EXAMPLE[ \t]*\n" nil t) + (goto-char (match-end 0)) + (while (not (looking-at "#\\+END_EXAMPLE")) + (insert ": ") + (beginning-of-line 2))) + (goto-char (point-min)) + (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t) + (add-text-properties (match-beginning 0) (match-end 0) + '(org-protected t))) + (while formatters + (setq fmt (pop formatters)) + (when (car fmt) + (goto-char (point-min)) + (while (re-search-forward (concat "^#\\+" (cadr fmt) + ":[ \t]*\\(.*\\)") nil t) + (replace-match "\\1" t) + (add-text-properties + (point-at-bol) (min (1+ (point-at-eol)) (point-max)) + '(org-protected t)))) + (goto-char (point-min)) + (while (re-search-forward + (concat "^#\\+" + (caddr fmt) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+" + (cadddr fmt) "\\>.*\n?") nil t) + (if (car fmt) + (add-text-properties (match-beginning 1) (1+ (match-end 1)) + '(org-protected t)) + (delete-region (match-beginning 0) (match-end 0)))))) + + ;; Protect quoted subtrees (goto-char (point-min)) - (while (re-search-forward "^#.*\n?" nil t) - (replace-match "")) + (while (re-search-forward re-quote nil t) + (goto-char (match-beginning 0)) + (end-of-line 1) + (add-text-properties (point) (org-end-of-subtree t) + '(org-protected t))) + + ;; Protect verbatim elements + (goto-char (point-min)) + (while (re-search-forward org-verbatim-re nil t) + (add-text-properties (match-beginning 4) (match-end 4) + '(org-protected t)) + (goto-char (1+ (match-end 4)))) + + ;; Remove subtrees that are commented + (goto-char (point-min)) + (while (re-search-forward re-commented nil t) + (goto-char (match-beginning 0)) + (delete-region (point) (org-end-of-subtree t))) + + ;; Remove special table lines + (when org-export-table-remove-special-lines + (goto-char (point-min)) + (while (re-search-forward "^[ \t]*|" nil t) + (beginning-of-line 1) + (if (or (looking-at "[ \t]*| *[!_^] *|") + (and (looking-at ".*?| *<[0-9]+> *|") + (not (looking-at ".*?| *[^ <|]")))) + (delete-region (max (point-min) (1- (point-at-bol))) + (point-at-eol)) + (end-of-line 1)))) + + ;; Specific LaTeX stuff + (when latexp + (require 'org-export-latex nil) + (org-export-latex-cleaned-string)) + + (when asciip + (org-export-ascii-clean-string)) + + ;; Specific HTML stuff + (when htmlp + ;; Convert LaTeX fragments to images + (when (plist-get parameters :LaTeX-fragments) + (org-format-latex + (concat "ltxpng/" (file-name-sans-extension + (file-name-nondirectory + org-current-export-file))) + org-current-export-dir nil "Creating LaTeX image %s")) + (message "Exporting...")) + + ;; Remove or replace comments + (goto-char (point-min)) + (while (re-search-forward "^#\\(.*\n?\\)" nil t) + (if commentsp + (progn (add-text-properties + (match-beginning 0) (match-end 0) '(org-protected t)) + (replace-match (format commentsp (match-string 1)) t t)) + (replace-match ""))) ;; Find matches for radio targets and turn them into internal links (goto-char (point-min)) @@ -16838,56 +24687,85 @@ translations. There is currently no way for users to extend this.") (replace-match "\\1 \\3") (goto-char (match-beginning 0)))) - ;; Convert LaTeX fragments to images - (when (memq :LaTeX-fragments parameters) - (org-format-latex - (concat "ltxpng/" (file-name-sans-extension - (file-name-nondirectory - org-current-export-file))) - org-current-export-dir nil "Creating LaTeX image %s")) - (message "Exporting...") ;; Normalize links: Convert angle and plain links into bracket links ;; Expand link abbreviations (goto-char (point-min)) (while (re-search-forward re-plain-link nil t) + (goto-char (1- (match-end 0))) (org-if-unprotected - (replace-match - (concat - (match-string 1) "[[" (match-string 2) ":" (match-string 3) "]]") - t t))) + (let* ((s (concat (match-string 1) "[[" (match-string 2) + ":" (match-string 3) "]]"))) + ;; added 'org-link face to links + (put-text-property 0 (length s) 'face 'org-link s) + (replace-match s t t)))) (goto-char (point-min)) (while (re-search-forward re-angle-link nil t) + (goto-char (1- (match-end 0))) (org-if-unprotected - (replace-match - (concat - (match-string 1) "[[" (match-string 2) ":" (match-string 3) "]]") - t t))) + (let* ((s (concat (match-string 1) "[[" (match-string 2) + ":" (match-string 3) "]]"))) + (put-text-property 0 (length s) 'face 'org-link s) + (replace-match s t t)))) (goto-char (point-min)) (while (re-search-forward org-bracket-link-regexp nil t) (org-if-unprotected - (replace-match - (concat "[[" (save-match-data - (org-link-expand-abbrev (match-string 1))) - "]" - (if (match-end 3) - (match-string 2) - (concat "[" (match-string 1) "]")) - "]") - t t))) + (let* ((s (concat "[[" (setq xx (save-match-data + (org-link-expand-abbrev (match-string 1)))) + "]" + (if (match-end 3) + (match-string 2) + (concat "[" xx "]")) + "]"))) + (put-text-property 0 (length s) 'face 'org-link s) + (replace-match s t t)))) ;; Find multiline emphasis and put them into single line - (when (memq :emph-multiline parameters) + (when (plist-get parameters :emph-multiline) (goto-char (point-min)) (while (re-search-forward org-emph-re nil t) - (org-if-unprotected - (subst-char-in-region (match-beginning 0) (match-end 0) ?\n ?\ t) - (goto-char (1- (match-end 0)))))) + (if (not (= (char-after (match-beginning 3)) + (char-after (match-beginning 4)))) + (org-if-unprotected + (subst-char-in-region (match-beginning 0) (match-end 0) + ?\n ?\ t) + (goto-char (1- (match-end 0)))) + (goto-char (1+ (match-beginning 0)))))) (setq rtn (buffer-string))) (kill-buffer " org-mode-tmp") rtn)) +(defun org-export-grab-title-from-buffer () + "Get a title for the current document, from looking at the buffer." + (let ((inhibit-read-only t)) + (save-excursion + (goto-char (point-min)) + (let ((end (save-excursion (outline-next-heading) (point)))) + (when (re-search-forward "^[ \t]*[^|# \t\r\n].*\n" end t) + ;; Mark the line so that it will not be exported as normal text. + (org-unmodified + (add-text-properties (match-beginning 0) (match-end 0) + (list :org-license-to-kill t))) + ;; Return the title string + (org-trim (match-string 0))))))) + +(defun org-export-get-title-from-subtree () + "Return subtree title and exclude it from export." + (let (title (m (mark))) + (save-excursion + (goto-char (region-beginning)) + (when (and (org-at-heading-p) + (>= (org-end-of-subtree t t) (region-end))) + ;; This is a subtree, we take the title from the first heading + (goto-char (region-beginning)) + (looking-at org-todo-line-regexp) + (setq title (match-string 3)) + (org-unmodified + (add-text-properties (point) (1+ (point-at-eol)) + (list :org-license-to-kill t))))) + title)) + (defun org-solidify-link-text (s &optional alist) "Take link text and make a safe target out of it." (save-match-data @@ -16898,6 +24776,15 @@ translations. There is currently no way for users to extend this.") (a (assoc rtn alist))) (or (cdr a) rtn)))) +(defun org-get-min-level (lines) + "Get the minimum level in LINES." + (let ((re "^\\(\\*+\\) ") l min) + (catch 'exit + (while (setq l (pop lines)) + (if (string-match re l) + (throw 'exit (org-tr-level (length (match-string 1 l)))))) + 1))) + ;; Variable holding the vector with section numbers (defvar org-section-numbers (make-vector org-level-max 0)) @@ -16947,6 +24834,7 @@ When LEVEL is non-nil, increase section numbers on that level." ;;; ASCII export (defvar org-last-level nil) ; dynamically scoped variable +(defvar org-min-level nil) ; dynamically scoped variable (defvar org-levels-open nil) ; dynamically scoped parameter (defvar org-ascii-current-indentation nil) ; For communication @@ -16959,16 +24847,14 @@ underlined headlines. The default is 3." (setq-default org-todo-line-regexp org-todo-line-regexp) (let* ((opt-plist (org-combine-plists (org-default-export-plist) (org-infile-export-plist))) - (region - (buffer-substring - (if (org-region-active-p) (region-beginning) (point-min)) - (if (org-region-active-p) (region-end) (point-max)))) + (region-p (org-region-active-p)) + (subtree-p + (when region-p + (save-excursion + (goto-char (region-beginning)) + (and (org-at-heading-p) + (>= (org-end-of-subtree t t) (region-end)))))) (custom-times org-display-custom-times) - (lines (org-export-find-first-heading-line - (org-skip-comments - (org-split-string - (org-cleaned-string-for-export region) - "[\r\n]")))) (org-ascii-current-indentation '(0 . 0)) (level 0) line txt (umax nil) @@ -16977,26 +24863,59 @@ underlined headlines. The default is 3." (filename (concat (file-name-as-directory (org-export-directory :ascii opt-plist)) (file-name-sans-extension - (file-name-nondirectory buffer-file-name)) + (or (and subtree-p + (org-entry-get (region-beginning) + "EXPORT_FILE_NAME" t)) + (file-name-nondirectory buffer-file-name))) ".txt")) + (filename (if (equal (file-truename filename) + (file-truename buffer-file-name)) + (concat filename ".txt") + filename)) (buffer (find-file-noselect filename)) (org-levels-open (make-vector org-level-max nil)) (odd org-odd-levels-only) - (date (format-time-string "%Y/%m/%d" (current-time))) - (time (format-time-string "%X" (org-current-time))) + (date (plist-get opt-plist :date)) (author (plist-get opt-plist :author)) - (title (or (plist-get opt-plist :title) + (title (or (and subtree-p (org-export-get-title-from-subtree)) + (plist-get opt-plist :title) + (and (not + (plist-get opt-plist :skip-before-1st-heading)) + (org-export-grab-title-from-buffer)) (file-name-sans-extension (file-name-nondirectory buffer-file-name)))) (email (plist-get opt-plist :email)) (language (plist-get opt-plist :language)) (quote-re0 (concat "^[ \t]*" org-quote-string "\\>")) ; (quote-re (concat "^\\(\\*+\\)\\([ \t]*" org-quote-string "\\>\\)")) - (text nil) (todo nil) - (lang-words nil)) + (lang-words nil) + (region + (buffer-substring + (if (org-region-active-p) (region-beginning) (point-min)) + (if (org-region-active-p) (region-end) (point-max)))) + (lines (org-split-string + (org-cleaned-string-for-export + region + :for-ascii t + :skip-before-1st-heading + (plist-get opt-plist :skip-before-1st-heading) + :drawers (plist-get opt-plist :drawers) + :verbatim-multiline t + :archived-trees + (plist-get opt-plist :archived-trees) + :add-text (plist-get opt-plist :text)) + "\n")) + thetoc have-headings first-heading-pos + table-open table-buffer) - (setq org-last-level 1) + (let ((inhibit-read-only t)) + (org-unmodified + (remove-text-properties (point-min) (point-max) + '(:org-license-to-kill t)))) + + (setq org-min-level (org-get-min-level lines)) + (setq org-last-level org-min-level) (org-init-section-numbers) (find-file-noselect filename) @@ -17008,10 +24927,10 @@ underlined headlines. The default is 3." (fundamental-mode) ;; create local variables for all options, to make sure all called ;; functions get the correct information - (mapcar (lambda (x) - (set (make-local-variable (cdr x)) - (plist-get opt-plist (car x)))) - org-export-plist-vars) + (mapc (lambda (x) + (set (make-local-variable (cdr x)) + (plist-get opt-plist (car x)))) + org-export-plist-vars) (org-set-local 'org-odd-levels-only odd) (setq umax (if arg (prefix-numeric-value arg) org-export-headline-levels)) @@ -17022,57 +24941,77 @@ underlined headlines. The default is 3." ;; File header (if title (org-insert-centered title ?=)) (insert "\n") - (if (or author email) + (if (and (or author email) + org-export-author-info) (insert (concat (nth 1 lang-words) ": " (or author "") (if email (concat " <" email ">") "") "\n"))) - (if (and date time) - (insert (concat (nth 2 lang-words) ": " date " " time "\n"))) - (if text (insert (concat (org-html-expand-for-ascii text) "\n\n"))) + + (cond + ((and date (string-match "%" date)) + (setq date (format-time-string date (current-time)))) + (date) + (t (setq date (format-time-string "%Y/%m/%d %X" (current-time))))) + + (if (and date org-export-time-stamp-file) + (insert (concat (nth 2 lang-words) ": " date"\n"))) (insert "\n\n") (if org-export-with-toc (progn - (insert (nth 3 lang-words) "\n" - (make-string (length (nth 3 lang-words)) ?=) "\n") - (mapcar '(lambda (line) - (if (string-match org-todo-line-regexp - line) - ;; This is a headline - (progn - (setq level (- (match-end 1) (match-beginning 1)) - level (org-tr-level level) - txt (match-string 3 line) - todo - (or (and org-export-mark-todo-in-toc - (match-beginning 2) - (not (equal (match-string 2 line) - org-done-string))) + (push (concat (nth 3 lang-words) "\n") thetoc) + (push (concat (make-string (length (nth 3 lang-words)) ?=) "\n") thetoc) + (mapc '(lambda (line) + (if (string-match org-todo-line-regexp + line) + ;; This is a headline + (progn + (setq have-headings t) + (setq level (- (match-end 1) (match-beginning 1)) + level (org-tr-level level) + txt (match-string 3 line) + todo + (or (and org-export-mark-todo-in-toc + (match-beginning 2) + (not (member (match-string 2 line) + org-done-keywords))) ; TODO, not DONE - (and org-export-mark-todo-in-toc - (= level umax-toc) - (org-search-todo-below - line lines level)))) - (setq txt (org-html-expand-for-ascii txt)) + (and org-export-mark-todo-in-toc + (= level umax-toc) + (org-search-todo-below + line lines level)))) + (setq txt (org-html-expand-for-ascii txt)) - (if (and (memq org-export-with-tags '(not-in-toc nil)) - (string-match "[ \t]+:[a-zA-Z0-9_@:]+:[ \t]*$" txt)) - (setq txt (replace-match "" t t txt))) - (if (string-match quote-re0 txt) - (setq txt (replace-match "" t t txt))) + (while (string-match org-bracket-link-regexp txt) + (setq txt + (replace-match + (match-string (if (match-end 2) 3 1) txt) + t t txt))) - (if org-export-with-section-numbers - (setq txt (concat (org-section-number level) - " " txt))) - (if (<= level umax-toc) - (progn - (insert - (make-string (* (1- level) 4) ?\ ) - (format (if todo "%s (*)\n" "%s\n") txt)) - (setq org-last-level level)) - )))) - lines))) + (if (and (memq org-export-with-tags '(not-in-toc nil)) + (string-match + (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$") + txt)) + (setq txt (replace-match "" t t txt))) + (if (string-match quote-re0 txt) + (setq txt (replace-match "" t t txt))) + + (if org-export-with-section-numbers + (setq txt (concat (org-section-number level) + " " txt))) + (if (<= level umax-toc) + (progn + (push + (concat + (make-string + (* (max 0 (- level org-min-level)) 4) ?\ ) + (format (if todo "%s (*)\n" "%s\n") txt)) + thetoc) + (setq org-last-level level)) + )))) + lines) + (setq thetoc (if have-headings (nreverse thetoc) nil)))) (org-init-section-numbers) (while (setq line (pop lines)) @@ -17089,14 +25028,60 @@ underlined headlines. The default is 3." (when custom-times (setq line (org-translate-time line))) (cond - ((string-match "^\\(\\*+\\)[ \t]*\\(.*\\)" line) + ((string-match "^\\(\\*+\\)[ \t]+\\(.*\\)" line) ;; a Headline + (setq first-heading-pos (or first-heading-pos (point))) (setq level (org-tr-level (- (match-end 1) (match-beginning 1))) txt (match-string 2 line)) (org-ascii-level-start level txt umax lines)) + + ((and org-export-with-tables + (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)" line)) + (if (not table-open) + ;; New table starts + (setq table-open t table-buffer nil)) + ;; Accumulate lines + (setq table-buffer (cons line table-buffer)) + (when (or (not lines) + (not (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)" + (car lines)))) + (setq table-open nil + table-buffer (nreverse table-buffer)) + (insert (mapconcat + (lambda (x) + (org-fix-indentation x org-ascii-current-indentation)) + (org-format-table-ascii table-buffer) + "\n") "\n"))) (t - (insert (org-fix-indentation line org-ascii-current-indentation) "\n")))) + (setq line (org-fix-indentation line org-ascii-current-indentation)) + (if (and org-export-with-fixed-width + (string-match "^\\([ \t]*\\)\\(:\\)" line)) + (setq line (replace-match "\\1" nil nil line))) + (insert line "\n")))) + (normal-mode) + + ;; insert the table of contents + (when thetoc + (goto-char (point-min)) + (if (re-search-forward "^[ \t]*\\[TABLE-OF-CONTENTS\\][ \t]*$" nil t) + (progn + (goto-char (match-beginning 0)) + (replace-match "")) + (goto-char first-heading-pos)) + (mapc 'insert thetoc) + (or (looking-at "[ \t]*\n[ \t]*\n") + (insert "\n\n"))) + + ;; Convert whitespace place holders + (goto-char (point-min)) + (let (beg end) + (while (setq beg (next-single-property-change (point) 'org-whitespace)) + (setq end (next-single-property-change beg 'org-whitespace)) + (goto-char beg) + (delete-region beg end) + (insert (make-string (- end beg) ?\ )))) + (save-buffer) ;; remove display and invisible chars (let (beg end) @@ -17113,6 +25098,16 @@ underlined headlines. The default is 3." (goto-char beg))) (goto-char (point-min)))) +(defun org-export-ascii-clean-string () + "Do extra work for ASCII export" + (goto-char (point-min)) + (while (re-search-forward org-verbatim-re nil t) + (goto-char (match-end 2)) + (backward-delete-char 1) (insert "'") + (goto-char (match-beginning 2)) + (delete-char 1) (insert "`") + (goto-char (match-end 2)))) + (defun org-search-todo-below (line lines level) "Search the subtree below LINE for any TODO entries." (let ((rest (cdr (memq line lines))) @@ -17124,8 +25119,8 @@ underlined headlines. The default is 3." (progn (setq lv (- (match-end 1) (match-beginning 1)) todo (and (match-beginning 2) - (not (equal (match-string 2 line) - org-done-string)))) + (not (member (match-string 2 line) + org-done-keywords)))) ; TODO, not DONE (if (<= lv level) (throw 'exit nil)) (if todo (throw 'exit t)))))))) @@ -17159,7 +25154,7 @@ underlined headlines. The default is 3." ;; find the indentation of the next non-empty line (catch 'stop (while lines - (if (string-match "^\\*" (car lines)) (throw 'stop nil)) + (if (string-match "^\\* " (car lines)) (throw 'stop nil)) (if (string-match "^\\([ \t]*\\)\\S-" (car lines)) (throw 'stop (setq ind (org-get-indentation (car lines))))) (pop lines))) @@ -17169,7 +25164,7 @@ underlined headlines. The default is 3." (insert "\n")) (setq char (nth (- umax level) (reverse org-export-ascii-underline))) (unless org-export-with-tags - (if (string-match "[ \t]+\\(:[a-zA-Z0-9_@:]+:\\)[ \t]*$" title) + (if (string-match (org-re "[ \t]+\\(:[[:alnum:]_@:]+:\\)[ \t]*$") title) (setq title (replace-match "" t t title)))) (if org-export-with-section-numbers (setq title (concat (org-section-number level) " " title))) @@ -17187,7 +25182,7 @@ continue to use it. The prefix arg ARG is passed through to the exporting command." (interactive (list (progn - (message "Export visible: [a]SCII [h]tml [b]rowse HTML [x]OXO [ ]keep buffer") + (message "Export visible: [a]SCII [h]tml [b]rowse HTML [H/R]uffer with HTML [x]OXO [ ]keep buffer") (read-char-exclusive)) current-prefix-arg)) (if (not (member type '(?a ?\C-a ?b ?\C-b ?h ?x ?\ ))) @@ -17198,11 +25193,19 @@ command." (?b . org-export-as-html-and-open) (?\C-b . org-export-as-html-and-open) (?h . org-export-as-html) + (?H . org-export-as-html-to-buffer) + (?R . org-export-region-as-html) (?x . org-export-as-xoxo))))) (keepp (equal type ?\ )) (file buffer-file-name) (buffer (get-buffer-create "*Org Export Visible*")) s e) + ;; Need to hack the drawers here. + (save-excursion + (goto-char (point-min)) + (while (re-search-forward org-drawer-regexp nil t) + (goto-char (match-beginning 1)) + (or (org-invisible-p) (org-flag-drawer nil)))) (with-current-buffer buffer (erase-buffer)) (save-excursion (setq s (goto-char (point-min))) @@ -17210,6 +25213,7 @@ command." (goto-char (org-find-invisible)) (append-to-buffer buffer s (point)) (setq s (goto-char (org-find-visible)))) + (org-cycle-hide-drawers 'all) (goto-char (point-min)) (unless keepp ;; Copy all comment lines to the end, to make sure #+ settings are @@ -17253,10 +25257,12 @@ Does include HTML export options as well as TODO and CATEGORY stuff." #+EMAIL: %s #+LANGUAGE: %s #+TEXT: Some descriptive text to be emitted. Several lines OK. -#+OPTIONS: H:%d num:%s toc:%s \\n:%s @:%s ::%s |:%s ^:%s *:%s TeX:%s LaTeX:%s +#+OPTIONS: H:%d num:%s toc:%s \\n:%s @:%s ::%s |:%s ^:%s -:%s f:%s *:%s TeX:%s LaTeX:%s skip:%s d:%s tags:%s #+CATEGORY: %s #+SEQ_TODO: %s #+TYP_TODO: %s +#+PRIORITIES: %c %c %c +#+DRAWERS: %s #+STARTUP: %s %s %s %s %s #+TAGS: %s #+ARCHIVE: %s @@ -17271,26 +25277,27 @@ Does include HTML export options as well as TODO and CATEGORY stuff." org-export-with-fixed-width org-export-with-tables org-export-with-sub-superscripts + org-export-with-special-strings + org-export-with-footnotes org-export-with-emphasize org-export-with-TeX-macros org-export-with-LaTeX-fragments + org-export-skip-text-before-1st-heading + org-export-with-drawers + org-export-with-tags (file-name-nondirectory buffer-file-name) - (if (equal org-todo-interpretation 'sequence) - (mapconcat 'identity org-todo-keywords " ") - "TODO FEEDBACK VERIFY DONE") - (if (equal org-todo-interpretation 'type) - (mapconcat 'identity org-todo-keywords " ") - "Me Jason Marie DONE") + "TODO FEEDBACK VERIFY DONE" + "Me Jason Marie DONE" + org-highest-priority org-lowest-priority org-default-priority + (mapconcat 'identity org-drawers " ") (cdr (assoc org-startup-folded '((nil . "showall") (t . "overview") (content . "content")))) (if org-odd-levels-only "odd" "oddeven") (if org-hide-leading-stars "hidestars" "showstars") (if org-startup-align-all-tables "align" "noalign") - (cond ((eq t org-log-done) "logdone") - ((not org-log-done) "nologging") - ((listp org-log-done) - (mapconcat (lambda (x) (concat "lognote" (symbol-name x))) - org-log-done " "))) + (cond ((eq org-log-done t) "logdone") + ((equal org-log-done 'note) "lognotedone") + ((not org-log-done) "nologdone")) (or (mapconcat (lambda (x) (cond ((equal '(:startgroup) x) "{") @@ -17325,6 +25332,7 @@ this line is also exported in fixed-width font." (beg (if regionp (region-beginning) (point))) (end (if regionp (region-end))) (nlines (or arg (if (and beg end) (count-lines beg end) 1))) + (case-fold-search nil) (re "[ \t]*\\(:\\)") off) (if regionp @@ -17348,12 +25356,12 @@ this line is also exported in fixed-width font." (save-excursion (org-back-to-heading) (if (looking-at (concat outline-regexp - "\\( +\\<" org-quote-string "\\>\\)")) + "\\( *\\<" org-quote-string "\\>[ \t]*\\)")) (replace-match "" t t nil 1) (if (looking-at outline-regexp) (progn (goto-char (match-end 0)) - (insert " " org-quote-string)))))))) + (insert org-quote-string " ")))))))) (defun org-export-as-html-and-open (arg) "Export the outline as HTML and immediately open it with a browser. @@ -17372,64 +25380,157 @@ emacs --batch --visit=MyFile --funcall org-export-as-html-batch" (org-export-as-html org-export-headline-levels 'hidden)) -(defun org-export-as-html (arg &optional hidden ext-plist) - "Export the outline as a pretty HTML file. -If there is an active region, export only the region. -The prefix ARG specifies how many levels of the outline should become -headlines. The default is 3. Lower levels will become bulleted lists. -When HIDDEN is non-nil, don't display the HTML buffer. -EXT-PLIST is a property list with external parameters overriding -org-mode's default settings, but still inferior to file-local settings." +(defun org-export-as-html-to-buffer (arg) + "Call `org-exort-as-html` with output to a temporary buffer. +No file is created. The prefix ARG is passed through to `org-export-as-html'." (interactive "P") + (org-export-as-html arg nil nil "*Org HTML Export*") + (switch-to-buffer-other-window "*Org HTML Export*")) + +(defun org-replace-region-by-html (beg end) + "Assume the current region has org-mode syntax, and convert it to HTML. +This can be used in any buffer. For example, you could write an +itemized list in org-mode syntax in an HTML buffer and then use this +command to convert it." + (interactive "r") + (let (reg html buf pop-up-frames) + (save-window-excursion + (if (org-mode-p) + (setq html (org-export-region-as-html + beg end t 'string)) + (setq reg (buffer-substring beg end) + buf (get-buffer-create "*Org tmp*")) + (with-current-buffer buf + (erase-buffer) + (insert reg) + (org-mode) + (setq html (org-export-region-as-html + (point-min) (point-max) t 'string))) + (kill-buffer buf))) + (delete-region beg end) + (insert html))) + +(defun org-export-region-as-html (beg end &optional body-only buffer) + "Convert region from BEG to END in org-mode buffer to HTML. +If prefix arg BODY-ONLY is set, omit file header, footer, and table of +contents, and only produce the region of converted text, useful for +cut-and-paste operations. +If BUFFER is a buffer or a string, use/create that buffer as a target +of the converted HTML. If BUFFER is the symbol `string', return the +produced HTML as a string and leave not buffer behind. For example, +a Lisp program could call this function in the following way: + + (setq html (org-export-region-as-html beg end t 'string)) + +When called interactively, the output buffer is selected, and shown +in a window. A non-interactive call will only retunr the buffer." + (interactive "r\nP") + (when (interactive-p) + (setq buffer "*Org HTML Export*")) + (let ((transient-mark-mode t) (zmacs-regions t) + rtn) + (goto-char end) + (set-mark (point)) ;; to activate the region + (goto-char beg) + (setq rtn (org-export-as-html + nil nil nil + buffer body-only)) + (if (fboundp 'deactivate-mark) (deactivate-mark)) + (if (and (interactive-p) (bufferp rtn)) + (switch-to-buffer-other-window rtn) + rtn))) + +(defvar html-table-tag nil) ; dynamically scoped into this. +(defun org-export-as-html (arg &optional hidden ext-plist + to-buffer body-only pub-dir) + "Export the outline as a pretty HTML file. +If there is an active region, export only the region. The prefix +ARG specifies how many levels of the outline should become +headlines. The default is 3. Lower levels will become bulleted +lists. When HIDDEN is non-nil, don't display the HTML buffer. +EXT-PLIST is a property list with external parameters overriding +org-mode's default settings, but still inferior to file-local +settings. When TO-BUFFER is non-nil, create a buffer with that +name and export to that buffer. If TO-BUFFER is the symbol +`string', don't leave any buffer behind but just return the +resulting HTML as a string. When BODY-ONLY is set, don't produce +the file header and footer, simply return the content of +..., without even the body tags themselves. When +PUB-DIR is set, use this as the publishing directory." + (interactive "P") + + ;; Make sure we have a file name when we need it. + (when (and (not (or to-buffer body-only)) + (not buffer-file-name)) + (if (buffer-base-buffer) + (org-set-local 'buffer-file-name + (with-current-buffer (buffer-base-buffer) + buffer-file-name)) + (error "Need a file name to be able to export."))) + (message "Exporting...") (setq-default org-todo-line-regexp org-todo-line-regexp) (setq-default org-deadline-line-regexp org-deadline-line-regexp) - (setq-default org-done-string org-done-string) + (setq-default org-done-keywords org-done-keywords) (setq-default org-maybe-keyword-time-regexp org-maybe-keyword-time-regexp) (let* ((opt-plist (org-combine-plists (org-default-export-plist) ext-plist (org-infile-export-plist))) (style (plist-get opt-plist :style)) + (html-extension (plist-get opt-plist :html-extension)) (link-validate (plist-get opt-plist :link-validation-function)) - valid + valid thetoc have-headings first-heading-pos (odd org-odd-levels-only) (region-p (org-region-active-p)) - (region - (buffer-substring - (if region-p (region-beginning) (point-min)) - (if region-p (region-end) (point-max)))) + (subtree-p + (when region-p + (save-excursion + (goto-char (region-beginning)) + (and (org-at-heading-p) + (>= (org-end-of-subtree t t) (region-end)))))) ;; The following two are dynamically scoped into other ;; routines below. - (org-current-export-dir (org-export-directory :html opt-plist)) + (org-current-export-dir + (or pub-dir (org-export-directory :html opt-plist))) (org-current-export-file buffer-file-name) - (all_lines - (org-skip-comments (org-split-string - (org-cleaned-string-for-export - region :emph-multiline :for-html - (if (plist-get opt-plist :LaTeX-fragments) - :LaTeX-fragments)) - "[\r\n]"))) - (lines (org-export-find-first-heading-line all_lines)) (level 0) (line "") (origline "") txt todo (umax nil) (umax-toc nil) - (filename (concat (file-name-as-directory - (org-export-directory :html opt-plist)) - (file-name-sans-extension - (file-name-nondirectory buffer-file-name)) - ".html")) - (current-dir (file-name-directory buffer-file-name)) - (buffer (find-file-noselect filename)) + (filename (if to-buffer nil + (expand-file-name + (concat + (file-name-sans-extension + (or (and subtree-p + (org-entry-get (region-beginning) + "EXPORT_FILE_NAME" t)) + (file-name-nondirectory buffer-file-name))) + "." html-extension) + (file-name-as-directory + (or pub-dir (org-export-directory :html opt-plist)))))) + (current-dir (if buffer-file-name + (file-name-directory buffer-file-name) + default-directory)) + (buffer (if to-buffer + (cond + ((eq to-buffer 'string) (get-buffer-create "*Org HTML Export*")) + (t (get-buffer-create to-buffer))) + (find-file-noselect filename))) (org-levels-open (make-vector org-level-max nil)) - (date (format-time-string "%Y/%m/%d" (current-time))) - (time (format-time-string "%X" (org-current-time))) + (date (plist-get opt-plist :date)) (author (plist-get opt-plist :author)) - (title (or (plist-get opt-plist :title) - (file-name-sans-extension - (file-name-nondirectory buffer-file-name)))) + (title (or (and subtree-p (org-export-get-title-from-subtree)) + (plist-get opt-plist :title) + (and (not + (plist-get opt-plist :skip-before-1st-heading)) + (org-export-grab-title-from-buffer)) + (and buffer-file-name + (file-name-sans-extension + (file-name-nondirectory buffer-file-name))) + "UNTITLED")) + (html-table-tag (plist-get opt-plist :html-table-tag)) (quote-re0 (concat "^[ \t]*" org-quote-string "\\>")) - (quote-re (concat "^\\(\\*+\\)\\([ \t]*" org-quote-string "\\>\\)")) + (quote-re (concat "^\\(\\*+\\)\\([ \t]+" org-quote-string "\\>\\)")) (inquote nil) (infixed nil) (in-local-list nil) @@ -17438,55 +25539,92 @@ org-mode's default settings, but still inferior to file-local settings." (llt org-plain-list-ordered-item-terminator) (email (plist-get opt-plist :email)) (language (plist-get opt-plist :language)) - (text (plist-get opt-plist :text)) (lang-words nil) (target-alist nil) tg (head-count 0) cnt (start 0) (coding-system (and (boundp 'buffer-file-coding-system) buffer-file-coding-system)) - (coding-system-for-write coding-system) - (save-buffer-coding-system coding-system) - (charset (and coding-system + (coding-system-for-write (or org-export-html-coding-system + coding-system)) + (save-buffer-coding-system (or org-export-html-coding-system + coding-system)) + (charset (and coding-system-for-write (fboundp 'coding-system-get) - (coding-system-get coding-system 'mime-charset))) + (coding-system-get coding-system-for-write + 'mime-charset))) + (region + (buffer-substring + (if region-p (region-beginning) (point-min)) + (if region-p (region-end) (point-max)))) + (lines + (org-split-string + (org-cleaned-string-for-export + region + :emph-multiline t + :for-html t + :skip-before-1st-heading + (plist-get opt-plist :skip-before-1st-heading) + :drawers (plist-get opt-plist :drawers) + :archived-trees + (plist-get opt-plist :archived-trees) + :add-text + (plist-get opt-plist :text) + :LaTeX-fragments + (plist-get opt-plist :LaTeX-fragments)) + "[\r\n]")) table-open type table-buffer table-orig-buffer - ind start-is-num starter + ind start-is-num starter didclose rpl path desc descp desc1 desc2 link ) + + (let ((inhibit-read-only t)) + (org-unmodified + (remove-text-properties (point-min) (point-max) + '(:org-license-to-kill t)))) + (message "Exporting...") - (setq org-last-level 1) + (setq org-min-level (org-get-min-level lines)) + (setq org-last-level org-min-level) (org-init-section-numbers) + (cond + ((and date (string-match "%" date)) + (setq date (format-time-string date (current-time)))) + (date) + (t (setq date (format-time-string "%Y/%m/%d %X" (current-time))))) + ;; Get the language-dependent settings (setq lang-words (or (assoc language org-export-language-setup) (assoc "en" org-export-language-setup))) ;; Switch to the output buffer - (if (or hidden t) - (set-buffer buffer) - (switch-to-buffer-other-window buffer)) - (erase-buffer) + (set-buffer buffer) + (let ((inhibit-read-only t)) (erase-buffer)) (fundamental-mode) + + (and (fboundp 'set-buffer-file-coding-system) + (set-buffer-file-coding-system coding-system-for-write)) + (let ((case-fold-search nil) (org-odd-levels-only odd)) ;; create local variables for all options, to make sure all called ;; functions get the correct information - (mapcar (lambda (x) - (set (make-local-variable (cdr x)) - (plist-get opt-plist (car x)))) - org-export-plist-vars) + (mapc (lambda (x) + (set (make-local-variable (cdr x)) + (plist-get opt-plist (car x)))) + org-export-plist-vars) (setq umax (if arg (prefix-numeric-value arg) org-export-headline-levels)) (setq umax-toc (if (integerp org-export-with-toc) (min org-export-with-toc umax) umax)) - - ;; File header - (insert (format - " @@ -17494,99 +25632,101 @@ lang=\"%s\" xml:lang=\"%s\"> %s - + %s " - language language (org-html-expand title) (or charset "iso-8859-1") - date time author style)) + language language (org-html-expand title) + (or charset "iso-8859-1") date author style)) + (insert (or (plist-get opt-plist :preamble) "")) - (insert (or (plist-get opt-plist :preamble) "")) + (when (plist-get opt-plist :auto-preamble) + (if title (insert (format org-export-html-title-format + (org-html-expand title)))))) - (when (plist-get opt-plist :auto-preamble) - (if title (insert (format org-export-html-title-format - (org-html-expand title)))) - (if text (insert "

    \n" (org-html-expand text) "

    "))) - - (if org-export-with-toc + (if (and org-export-with-toc (not body-only)) (progn - (insert (format "%s\n" - org-export-html-toplevel-hlevel - (nth 3 lang-words) - org-export-html-toplevel-hlevel)) - (insert "
    \n" thetoc)) + (setq thetoc (if have-headings (nreverse thetoc) nil)))) + (setq head-count 0) (org-init-section-numbers) @@ -17594,7 +25734,7 @@ lang=\"%s\" xml:lang=\"%s\"> (catch 'nextline ;; end of quote section? - (when (and inquote (string-match "^\\*+" line)) + (when (and inquote (string-match "^\\*+ " line)) (insert "\n") (setq inquote nil)) ;; inside a quote section? @@ -17618,7 +25758,17 @@ lang=\"%s\" xml:lang=\"%s\"> ;; Protected HTML (when (get-text-property 0 'org-protected line) - (insert line "\n") + (let (par) + (when (re-search-backward + "\\(

    \\)\\([ \t\r\n]*\\)\\=" (- (point) 100) t) + (setq par (match-string 1)) + (replace-match "\\2\n")) + (insert line "\n") + (while (and lines + (or (= (length (car lines)) 0) + (get-text-property 0 'org-protected (car lines)))) + (insert (pop lines) "\n")) + (and par (insert "

    \n"))) (throw 'nextline nil)) ;; Horizontal line @@ -17652,7 +25802,8 @@ lang=\"%s\" xml:lang=\"%s\"> ;; replace "&" by "&", "<" and ">" by "<" and ">" ;; handle @<..> HTML tags (replace "@>..<" by "<..>") ;; Also handle sub_superscripts and checkboxes - (setq line (org-html-expand line)) + (or (string-match org-table-hline-regexp line) + (setq line (org-html-expand line))) ;; Format the links (setq start 0) @@ -17676,9 +25827,10 @@ lang=\"%s\" xml:lang=\"%s\"> (setq rpl (concat "" desc ""))) - ((member type '("http" "https")) ; FIXME: need to test this. + ((member type '("http" "https")) ;; standard URL, just check if we need to inline an image (if (and (or (eq t org-export-html-inline-images) (and org-export-html-inline-images (not descp))) @@ -17709,7 +25861,7 @@ lang=\"%s\" xml:lang=\"%s\"> (string-match "\\.org$" thefile)) (setq thefile (concat (substring thefile 0 (match-beginning 0)) - ".html")) + "." html-extension)) (if (and search ;; make sure this is can be used as target search (not (string-match "^[0-9]*$" search)) @@ -17735,24 +25887,43 @@ lang=\"%s\" xml:lang=\"%s\"> ">")))) (setq line (replace-match rpl t t line) start (+ start (length rpl)))) + ;; TODO items (if (and (string-match org-todo-line-regexp line) (match-beginning 2)) - (if (equal (match-string 2 line) org-done-string) - (setq line (replace-match - "\\2" - t nil line 2)) - (setq line (replace-match "\\2" - t nil line 2)))) + + (setq line + (concat (substring line 0 (match-beginning 2)) + "" (match-string 2 line) + "" (substring line (match-end 2))))) + + ;; Does this contain a reference to a footnote? + (when org-export-with-footnotes + (setq start 0) + (while (string-match "\\([^* \t].*?\\)\\[\\([0-9]+\\)\\]" line start) + (if (get-text-property (match-beginning 2) 'org-protected line) + (setq start (match-end 2)) + (let ((n (match-string 2 line))) + (setq line + (replace-match + (format + "%s%s" + (match-string 1 line) n n n) + t t line)))))) (cond - ((string-match "^\\(\\*+\\)[ \t]*\\(.*\\)" line) + ((string-match "^\\(\\*+\\)[ \t]+\\(.*\\)" line) ;; This is a headline (setq level (org-tr-level (- (match-end 1) (match-beginning 1))) txt (match-string 2 line)) (if (string-match quote-re0 txt) (setq txt (replace-match "" t t txt))) - (if (<= level umax) (setq head-count (+ head-count 1))) + (if (<= level (max umax umax-toc)) + (setq head-count (+ head-count 1))) (when in-local-list ;; Close any local lists before inserting a new header line (while local-list-num @@ -17761,6 +25932,7 @@ lang=\"%s\" xml:lang=\"%s\"> (pop local-list-num)) (setq local-list-indent nil in-local-list nil)) + (setq first-heading-pos (or first-heading-pos (point))) (org-html-level-start level txt umax (and org-export-with-toc (<= level umax)) head-count) @@ -17791,7 +25963,7 @@ lang=\"%s\" xml:lang=\"%s\"> (cond ((eq llt t) "^\\([ \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+[.)]\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)") ((= llt ?.) "^\\([ \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+\\.\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)") - ((= llt ?\)) "^\\( \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+)\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)") + ((= llt ?\)) "^\\([ \t]*\\)\\(\\([-+*] \\)\\|\\([0-9]+)\\) \\)?\\( *[^ \t\n\r]\\|[ \t]*$\\)") (t (error "Invalid value of `org-plain-list-ordered-item-terminator'"))) line) (setq ind (org-get-string-indentation line) @@ -17801,11 +25973,15 @@ lang=\"%s\" xml:lang=\"%s\"> line (substring line (match-beginning 5))) (unless (string-match "[^ \t]" line) ;; empty line. Pretend indentation is large. - (setq ind (1+ (or (car local-list-indent) 1)))) + (setq ind (if org-empty-line-terminates-plain-lists + 0 + (1+ (or (car local-list-indent) 1))))) + (setq didclose nil) (while (and in-local-list (or (and (= ind (car local-list-indent)) (not starter)) (< ind (car local-list-indent)))) + (setq didclose t) (org-close-li) (insert (if (car local-list-num) "\n" "")) (pop local-list-num) (pop local-list-indent) @@ -17814,7 +25990,7 @@ lang=\"%s\" xml:lang=\"%s\"> ((and starter (or (not in-local-list) (> ind (car local-list-indent)))) - ;; Start new (level of ) list + ;; Start new (level of) list (org-close-par-maybe) (insert (if start-is-num "

      \n
    1. \n" "
        \n
      • \n")) (push start-is-num local-list-num) @@ -17823,7 +25999,10 @@ lang=\"%s\" xml:lang=\"%s\"> (starter ;; continue current list (org-close-li) - (insert "
      • \n"))) + (insert "
      • \n")) + (didclose + ;; we did close a list, normal text follows: need

        + (org-open-par))) (if (string-match "^[ \t]*\\[\\([X ]\\)\\]" line) (setq line (replace-match @@ -17837,6 +26016,14 @@ lang=\"%s\" xml:lang=\"%s\"> ;; also start a new paragraph. (if (string-match "^ [-+*]-\\|^[ \t]*$" line) (org-open-par)) + ;; Is this the start of a footnote? + (when org-export-with-footnotes + (when (string-match "^[ \t]*\\[\\([0-9]+\\)\\]" line) + (org-close-par-maybe) + (let ((n (match-string 1 line))) + (setq line (replace-match + (format "

        %s" n n n) t t line))))) + ;; Check if the line break needs to be conserved (cond ((string-match "\\\\\\\\[ \t]*$" line) @@ -17860,24 +26047,52 @@ lang=\"%s\" xml:lang=\"%s\"> (and org-export-with-toc (<= level umax)) head-count) - (when (plist-get opt-plist :auto-postamble) - (when author - (insert "

        " - (nth 1 lang-words) ": " author "\n") - (when email - (insert "<" - email ">\n")) - (insert "

        \n")) - (when (and date time) - (insert "

        " - (nth 2 lang-words) ": " - date " " time "

        \n"))) + (unless body-only + (when (plist-get opt-plist :auto-postamble) + (insert "
        ") + (when (and org-export-author-info author) + (insert "

        " + (nth 1 lang-words) ": " author "\n") + (when email + (if (listp (split-string email ",+ *")) + (mapc (lambda(e) + (insert "<" + e ">\n")) + (split-string email ",+ *")) + (insert "<" + email ">\n"))) + (insert "

        \n")) + (when (and date org-export-time-stamp-file) + (insert "

        " + (nth 2 lang-words) ": " + date "

        \n")) + (insert "
        ")) + + (if org-export-html-with-timestamp + (insert org-export-html-html-helper-timestamp)) + (insert (or (plist-get opt-plist :postamble) "")) + (insert "\n\n")) - (if org-export-html-with-timestamp - (insert org-export-html-html-helper-timestamp)) - (insert (or (plist-get opt-plist :postamble) "")) - (insert "\n\n") (normal-mode) + (if (eq major-mode default-major-mode) (html-mode)) + + ;; insert the table of contents + (goto-char (point-min)) + (when thetoc + (if (or (re-search-forward + "

        \\s-*\\[TABLE-OF-CONTENTS\\]\\s-*

        " nil t) + (re-search-forward + "\\[TABLE-OF-CONTENTS\\]" nil t)) + (progn + (goto-char (match-beginning 0)) + (replace-match "")) + (goto-char first-heading-pos) + (when (looking-at "\\s-*

        ") + (goto-char (match-end 0)) + (insert "\n"))) + (insert "
        \n") + (mapc 'insert thetoc) + (insert "
        \n")) ;; remove empty paragraphs and lists (goto-char (point-min)) (while (re-search-forward "

        [ \r\n\t]*

        " nil t) @@ -17885,13 +26100,76 @@ lang=\"%s\" xml:lang=\"%s\"> (goto-char (point-min)) (while (re-search-forward "
      • [ \r\n\t]*
      • \n?" nil t) (replace-match "")) - (save-buffer) (goto-char (point-min)) - (message "Exporting... done")))) + (while (re-search-forward "
      \\s-*
        \n?" nil t) + (replace-match "")) + ;; Convert whitespace place holders + (goto-char (point-min)) + (let (beg end n) + (while (setq beg (next-single-property-change (point) 'org-whitespace)) + (setq n (get-text-property beg 'org-whitespace) + end (next-single-property-change beg 'org-whitespace)) + (goto-char beg) + (delete-region beg end) + (insert (format "%s" + (make-string n ?x))))) + (or to-buffer (save-buffer)) + (goto-char (point-min)) + (message "Exporting... done") + (if (eq to-buffer 'string) + (prog1 (buffer-substring (point-min) (point-max)) + (kill-buffer (current-buffer))) + (current-buffer))))) +(defvar org-table-colgroup-info nil) +(defun org-format-table-ascii (lines) + "Format a table for ascii export." + (if (stringp lines) + (setq lines (org-split-string lines "\n"))) + (if (not (string-match "^[ \t]*|" (car lines))) + ;; Table made by table.el - test for spanning + lines + + ;; A normal org table + ;; Get rid of hlines at beginning and end + (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines))) + (setq lines (nreverse lines)) + (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines))) + (setq lines (nreverse lines)) + (when org-export-table-remove-special-lines + ;; Check if the table has a marking column. If yes remove the + ;; column and the special lines + (setq lines (org-table-clean-before-export lines))) + ;; Get rid of the vertical lines except for grouping + (let ((vl (org-colgroup-info-to-vline-list org-table-colgroup-info)) + rtn line vl1 start) + (while (setq line (pop lines)) + (if (string-match org-table-hline-regexp line) + (and (string-match "|\\(.*\\)|" line) + (setq line (replace-match " \\1" t nil line))) + (setq start 0 vl1 vl) + (while (string-match "|" line start) + (setq start (match-end 0)) + (or (pop vl1) (setq line (replace-match " " t t line))))) + (push line rtn)) + (nreverse rtn)))) + +(defun org-colgroup-info-to-vline-list (info) + (let (vl new last) + (while info + (setq last new new (pop info)) + (if (or (memq last '(:end :startend)) + (memq new '(:start :startend))) + (push t vl) + (push nil vl))) + (setq vl (nreverse vl)) + (and vl (setcar vl nil)) + vl)) (defun org-format-table-html (lines olines) "Find out which HTML converter to use and return the HTML code." + (if (stringp lines) + (setq lines (org-split-string lines "\n"))) (if (string-match "^[ \t]*|" (car lines)) ;; A normal org table (org-format-org-table-html lines) @@ -17931,7 +26209,7 @@ lang=\"%s\" xml:lang=\"%s\"> (lambda (x) (string-match "^[ \t]*|-" x)) (cdr lines))))) (nlines 0) fnum i - tbopen line fields html) + tbopen line fields html gr colgropen) (if splice (setq head nil)) (unless splice (push (if head "" "") html)) (setq tbopen t) @@ -17957,8 +26235,10 @@ lang=\"%s\" xml:lang=\"%s\"> (string-match org-table-number-regexp x)) (incf (aref fnum i))) (if head - (concat "" x "") - (concat "" x ""))) + (concat (car org-export-table-header-tags) x + (cdr org-export-table-header-tags)) + (concat (car org-export-table-data-tags) x + (cdr org-export-table-data-tags)))) fields "") "") html))) @@ -17966,48 +26246,75 @@ lang=\"%s\" xml:lang=\"%s\"> (unless splice (push "\n" html)) (setq html (nreverse html)) (unless splice - ;; Put in COL tags with the alignment (unfortuntely often ignored...) + ;; Put in col tags with the alignment (unfortuntely often ignored...) (push (mapconcat (lambda (x) - (format "" + (setq gr (pop org-table-colgroup-info)) + (format "%s%s" + (if (memq gr '(:start :startend)) + (prog1 + (if colgropen "\n" "") + (setq colgropen t)) + "") (if (> (/ (float x) nlines) org-table-number-fraction) - "right" "left"))) + "right" "left") + (if (memq gr '(:end :startend)) + (progn (setq colgropen nil) "") + ""))) fnum "") html) - (push org-export-html-table-tag html)) + (if colgropen (setq html (cons (car html) (cons "" (cdr html))))) + (push html-table-tag html)) (concat (mapconcat 'identity html "\n") "\n"))) (defun org-table-clean-before-export (lines) "Check if the table has a marking column. If yes remove the column and the special lines." + (setq org-table-colgroup-info nil) (if (memq nil (mapcar (lambda (x) (or (string-match "^[ \t]*|-" x) (string-match "^[ \t]*| *\\([#!$*_^ /]\\) *|" x))) lines)) (progn - (setq org-table-clean-did-remove-column-1 nil) - lines) - (setq org-table-clean-did-remove-column-1 t) + (setq org-table-clean-did-remove-column nil) + (delq nil + (mapcar + (lambda (x) + (cond + ((string-match "^[ \t]*| */ *|" x) + (setq org-table-colgroup-info + (mapcar (lambda (x) + (cond ((member x '("<" "<")) :start) + ((member x '(">" ">")) :end) + ((member x '("<>" "<>")) :startend) + (t nil))) + (org-split-string x "[ \t]*|[ \t]*"))) + nil) + (t x))) + lines))) + (setq org-table-clean-did-remove-column t) (delq nil (mapcar - (lambda (x) (if (string-match "^[ \t]*| *[!_^/] *|" x) - nil ; ignore this line - (and (or (string-match "^[ \t]*|-+\\+" x) - (string-match "^[ \t]*|[^|]*|" x)) - (replace-match "|" t t x)))) + (lambda (x) + (cond + ((string-match "^[ \t]*| */ *|" x) + (setq org-table-colgroup-info + (mapcar (lambda (x) + (cond ((member x '("<" "<")) :start) + ((member x '(">" ">")) :end) + ((member x '("<>" "<>")) :startend) + (t nil))) + (cdr (org-split-string x "[ \t]*|[ \t]*")))) + nil) + ((string-match "^[ \t]*| *[!_^/] *|" x) + nil) ; ignore this line + ((or (string-match "^\\([ \t]*\\)|-+\\+" x) + (string-match "^\\([ \t]*\\)|[^|]*|" x)) + ;; remove the first column + (replace-match "\\1|" t nil x)))) lines)))) -(defun org-fake-empty-table-line (line) - "Replace everything except \"|\" with spaces." - (let ((i (length line)) - (newstr (copy-sequence line))) - (while (> i 0) - (setq i (1- i)) - (if (not (eq (aref newstr i) ?|)) - (aset newstr i ?\ ))) - newstr)) - (defun org-format-table-table-html (lines) "Format a table generated by table.el into HTML. This conversion does *not* use `table-generate-source' from table.el. @@ -18016,7 +26323,7 @@ But it has the disadvantage, that no cell- or row-spanning is allowed." (let (line field-buffer (head org-export-highlight-first-table-line) fields html empty) - (setq html (concat org-export-html-table-tag "\n")) + (setq html (concat html-table-tag "\n")) (while (setq line (pop lines)) (setq empty " ") (catch 'next-line @@ -18024,17 +26331,21 @@ But it has the disadvantage, that no cell- or row-spanning is allowed." (progn (if field-buffer (progn - (setq html (concat - html - "" - (mapconcat - (lambda (x) - (if (equal x "") (setq x empty)) - (if head - (concat "" x "\n") - (concat "" x "\n"))) - field-buffer "\n") - "\n")) + (setq + html + (concat + html + "" + (mapconcat + (lambda (x) + (if (equal x "") (setq x empty)) + (if head + (concat (car org-export-table-header-tags) x + (cdr org-export-table-header-tags)) + (concat (car org-export-table-data-tags) x + (cdr org-export-table-data-tags)))) + field-buffer "\n") + "\n")) (setq head nil) (setq field-buffer nil))) ;; Ignore this line @@ -18110,18 +26421,24 @@ But it has the disadvantage, that Org-mode's HTML conversions cannot be used." (defun org-export-cleanup-toc-line (s) "Remove tags and time staps from lines going into the toc." - (if (string-match " +:[a-zA-Z0-9_@:]+: *$" s) - (setq s (replace-match "" t t s))) + (when (memq org-export-with-tags '(not-in-toc nil)) + (if (string-match (org-re " +:[[:alnum:]_@:]+: *$") s) + (setq s (replace-match "" t t s)))) (when org-export-remove-timestamps-from-toc (while (string-match org-maybe-keyword-time-regexp s) (setq s (replace-match "" t t s)))) + (while (string-match org-bracket-link-regexp s) + (setq s (replace-match (match-string (if (match-end 3) 3 1) s) + t t s))) s) (defun org-html-expand (string) "Prepare STRING for HTML export. Applies all active conversions. If there are links in the string, don't modify these." - (let* (m s l res) - (while (setq m (string-match org-bracket-link-regexp string)) + (let* ((re (concat org-bracket-link-regexp "\\|" + (org-re "[ \t]+\\(:[[:alnum:]_@:]+:\\)[ \t]*$"))) + m s l res) + (while (setq m (string-match re string)) (setq s (substring string 0 m) l (match-string 0 string) string (substring string (match-end 0))) @@ -18134,21 +26451,26 @@ If there are links in the string, don't modify these." "Apply all active conversions to translate special ASCII to HTML." (setq s (org-html-protect s)) (if org-export-html-expand - (while (string-match "@<\\([^&]*\\)>" s) - (setq s (replace-match "<\\1>" t nil s)))) + (let ((start 0)) + (while (string-match "@<\\([^&]*\\)>" s) + (setq s (replace-match "<\\1>" t nil s))))) (if org-export-with-emphasize (setq s (org-export-html-convert-emphasize s))) + (if org-export-with-special-strings + (setq s (org-export-html-convert-special-strings s))) (if org-export-with-sub-superscripts (setq s (org-export-html-convert-sub-super s))) (if org-export-with-TeX-macros (let ((start 0) wd ass) (while (setq start (string-match "\\\\\\([a-zA-Z]+\\)" s start)) - (setq wd (match-string 1 s)) - (if (setq ass (assoc wd org-html-entities)) - (setq s (replace-match (or (cdr ass) - (concat "&" (car ass) ";")) - t t s)) - (setq start (+ start (length wd))))))) + (if (get-text-property (match-beginning 0) 'org-protected s) + (setq start (match-end 0)) + (setq wd (match-string 1 s)) + (if (setq ass (assoc wd org-html-entities)) + (setq s (replace-match (or (cdr ass) + (concat "&" (car ass) ";")) + t t s)) + (setq start (+ start (length wd)))))))) s) (defun org-create-multibrace-regexp (left right n) @@ -18179,27 +26501,74 @@ stacked delimiters is N. Escaping delimiters is not possible." "\\(\\(?:\\*\\|[-+]?[^-+*!@#$%^_ \t\r\n,:\"?<>~;./{}=()]+\\)\\)\\)") "The regular expression matching a sub- or superscript.") +(defvar org-match-substring-with-braces-regexp + (concat + "\\([^\\]\\)\\([_^]\\)\\(" + "\\(" (org-create-multibrace-regexp "{" "}" org-match-sexp-depth) "\\)" + "\\)") + "The regular expression matching a sub- or superscript, forcing braces.") + +(defconst org-export-html-special-string-regexps + '(("\\\\-" . "­") + ("---\\([^-]\\)" . "—\\1") + ("--\\([^-]\\)" . "–\\1") + ("\\.\\.\\." . "…")) + "Regular expressions for special string conversion.") + +(defun org-export-html-convert-special-strings (string) + "Convert special characters in STRING to HTML." + (let ((all org-export-html-special-string-regexps) + e a re rpl start) + (while (setq a (pop all)) + (setq re (car a) rpl (cdr a) start 0) + (while (string-match re string start) + (if (get-text-property (match-beginning 0) 'org-protected string) + (setq start (match-end 0)) + (setq string (replace-match rpl t nil string))))) + string)) + (defun org-export-html-convert-sub-super (string) "Convert sub- and superscripts in STRING to HTML." - (let (key c) - (while (string-match org-match-substring-regexp string) - (setq key (if (string= (match-string 2 string) "_") "sub" "sup")) - (setq c (or (match-string 8 string) - (match-string 6 string) - (match-string 5 string))) - (setq string (replace-match - (concat (match-string 1 string) - "<" key ">" c "") - t t string))) + (let (key c (s 0) (requireb (eq org-export-with-sub-superscripts '{}))) + (while (string-match org-match-substring-regexp string s) + (cond + ((and requireb (match-end 8)) (setq s (match-end 2))) + ((get-text-property (match-beginning 2) 'org-protected string) + (setq s (match-end 2))) + (t + (setq s (match-end 1) + key (if (string= (match-string 2 string) "_") "sub" "sup") + c (or (match-string 8 string) + (match-string 6 string) + (match-string 5 string)) + string (replace-match + (concat (match-string 1 string) + "<" key ">" c "") + t t string))))) (while (string-match "\\\\\\([_^]\\)" string) - (setq string (replace-match (match-string 1 string) t t string)))) - string) + (setq string (replace-match (match-string 1 string) t t string))) + string)) (defun org-export-html-convert-emphasize (string) "Apply emphasis." - (while (string-match org-emph-re string) - (setq string (replace-match (concat "\\1" (nth 2 (assoc (match-string 3 string) org-emphasis-alist)) "\\4" (nth 3 (assoc (match-string 3 string) org-emphasis-alist)) "\\5") t nil string))) - string) + (let ((s 0) rpl) + (while (string-match org-emph-re string s) + (if (not (equal + (substring string (match-beginning 3) (1+ (match-beginning 3))) + (substring string (match-beginning 4) (1+ (match-beginning 4))))) + (setq s (match-beginning 0) + rpl + (concat + (match-string 1 string) + (nth 2 (assoc (match-string 3 string) org-emphasis-alist)) + (match-string 4 string) + (nth 3 (assoc (match-string 3 string) + org-emphasis-alist)) + (match-string 5 string)) + string (replace-match rpl t t string) + s (+ s (- (length rpl) 2))) + (setq s (1+ s)))) + string)) (defvar org-par-open nil) (defun org-open-par () @@ -18216,26 +26585,23 @@ stacked delimiters is N. Escaping delimiters is not possible." "Close
      • if necessary." (org-close-par-maybe) (insert "
      • \n")) -; (when (save-excursion -; (re-search-backward "" nil t)) -; (if (member (match-string 0) '("
      " "
    " "
  • ")) -; (insert "
  • ")))) +(defvar body-only) ; dynamically scoped into this. (defun org-html-level-start (level title umax with-toc head-count) "Insert a new level in HTML export. When TITLE is nil, just close all open levels." (org-close-par-maybe) - (let ((l (1+ (max level umax)))) - (while (<= l org-level-max) + (let ((l org-level-max)) + (while (>= l level) (if (aref org-levels-open (1- l)) (progn - (org-html-level-close l) + (org-html-level-close l umax) (aset org-levels-open (1- l) nil))) - (setq l (1+ l))) + (setq l (1- l))) (when title ;; If title is nil, this means this function is called to close ;; all levels, so the rest is done only if title is given - (when (string-match "\\(:[a-zA-Z0-9_@:]+:\\)[ \t]*$" title) + (when (string-match (org-re "\\(:[[:alnum:]_@:]+:\\)[ \t]*$") title) (setq title (replace-match (if org-export-with-tags (save-match-data @@ -18256,19 +26622,22 @@ When TITLE is nil, just close all open levels." (aset org-levels-open (1- level) t) (org-close-par-maybe) (insert "
      \n
    • " title "
      \n"))) - (if org-export-with-section-numbers + (aset org-levels-open (1- level) t) + (if (and org-export-with-section-numbers (not body-only)) (setq title (concat (org-section-number level) " " title))) (setq level (+ level org-export-html-toplevel-hlevel -1)) (if with-toc - (insert (format "\n%s\n" - level head-count title level)) - (insert (format "\n%s\n" level title level))) + (insert (format "\n
      \n%s\n" + level level head-count title level)) + (insert (format "\n
      \n%s\n" level level title level))) (org-open-par))))) -(defun org-html-level-close (&rest args) +(defun org-html-level-close (level max-outline-level) "Terminate one level in HTML export." - (org-close-li) - (insert "
    ")) + (if (<= level max-outline-level) + (insert "\n") + (org-close-li) + (insert "\n"))) ;;; iCalendar export @@ -18300,11 +26669,12 @@ The file is stored under the name `org-combined-agenda-icalendar-file'." If COMBINE is non-nil, combine all calendar entries into a single large file and store it under the name `org-combined-agenda-icalendar-file'." (save-excursion + (org-prepare-agenda-buffers files) (let* ((dir (org-export-directory :ical (list :publishing-directory org-export-publishing-directory))) file ical-file ical-buffer category started org-agenda-new-buffers) - + (and (get-buffer "*ical-tmp*") (kill-buffer "*ical-tmp*")) (when combine (setq ical-file (if (file-name-absolute-p org-combined-agenda-icalendar-file) @@ -18349,78 +26719,197 @@ the iCalendar file.") (defun org-print-icalendar-entries (&optional combine) "Print iCalendar entries for the current Org-mode file to `standard-output'. When COMBINE is non nil, add the category to each line." - (let ((re2 (concat "--?-?\\(" org-ts-regexp "\\)")) - (org-category-table (org-get-category-table)) + (let ((re1 (concat org-ts-regexp "\\|<%%([^>\n]+>")) + (re2 (concat "--?-?\\(" org-ts-regexp "\\)")) (dts (org-ical-ts-to-string (format-time-string (cdr org-time-stamp-formats) (current-time)) "DTSTART")) - hd ts ts2 state status (inc t) pos - scheduledp deadlinep tmp pri category) + hd ts ts2 state status (inc t) pos b sexp rrule + scheduledp deadlinep tmp pri category entry location summary desc + (sexp-buffer (get-buffer-create "*ical-tmp*"))) + (org-refresh-category-properties) (save-excursion (goto-char (point-min)) - (while (re-search-forward org-ts-regexp nil t) - (setq pos (match-beginning 0) - ts (match-string 0) - inc t - hd (org-get-heading) - category (org-get-category)) - (if (looking-at re2) - (progn - (goto-char (match-end 0)) - (setq ts2 (match-string 1) inc nil)) - (setq ts2 ts - tmp (buffer-substring (max (point-min) + (while (re-search-forward re1 nil t) + (catch :skip + (org-agenda-skip) + (when (boundp 'org-icalendar-verify-function) + (unless (funcall org-icalendar-verify-function) + (outline-next-heading) + (backward-char 1) + (throw :skip nil))) + (setq pos (match-beginning 0) + ts (match-string 0) + inc t + hd (org-get-heading) + summary (org-icalendar-cleanup-string + (org-entry-get nil "SUMMARY")) + desc (org-icalendar-cleanup-string + (or (org-entry-get nil "DESCRIPTION") + (and org-icalendar-include-body (org-get-entry))) + t org-icalendar-include-body) + location (org-icalendar-cleanup-string + (org-entry-get nil "LOCATION")) + category (org-get-category)) + (if (looking-at re2) + (progn + (goto-char (match-end 0)) + (setq ts2 (match-string 1) inc nil)) + (setq tmp (buffer-substring (max (point-min) (- pos org-ds-keyword-length)) - pos) - deadlinep (string-match org-deadline-regexp tmp) - scheduledp (string-match org-scheduled-regexp tmp) - ;; donep (org-entry-is-done-p) - )) - (if (or (string-match org-tr-regexp hd) - (string-match org-ts-regexp hd)) - (setq hd (replace-match "" t t hd))) - (if (string-match org-bracket-link-regexp hd) - (setq hd (replace-match (if (match-end 3) (match-string 3 hd) - (match-string 1 hd)) - t t hd))) - (if deadlinep (setq hd (concat "DL: " hd))) - (if scheduledp (setq hd (concat "S: " hd))) - (princ (format "BEGIN:VEVENT + pos) + ts2 (if (string-match "[0-9]\\{1,2\\}:[0-9][0-9]-\\([0-9]\\{1,2\\}:[0-9][0-9]\\)" ts) + (progn + (setq inc nil) + (replace-match "\\1" t nil ts)) + ts) + deadlinep (string-match org-deadline-regexp tmp) + scheduledp (string-match org-scheduled-regexp tmp) + ;; donep (org-entry-is-done-p) + )) + (if (or (string-match org-tr-regexp hd) + (string-match org-ts-regexp hd)) + (setq hd (replace-match "" t t hd))) + (if (string-match "\\+\\([0-9]+\\)\\([dwmy]\\)>" ts) + (setq rrule + (concat "\nRRULE:FREQ=" + (cdr (assoc + (match-string 2 ts) + '(("d" . "DAILY")("w" . "WEEKLY") + ("m" . "MONTHLY")("y" . "YEARLY")))) + ";INTERVAL=" (match-string 1 ts))) + (setq rrule "")) + (setq summary (or summary hd)) + (if (string-match org-bracket-link-regexp summary) + (setq summary + (replace-match (if (match-end 3) + (match-string 3 summary) + (match-string 1 summary)) + t t summary))) + (if deadlinep (setq summary (concat "DL: " summary))) + (if scheduledp (setq summary (concat "S: " summary))) + (if (string-match "\\`<%%" ts) + (with-current-buffer sexp-buffer + (insert (substring ts 1 -1) " " summary "\n")) + (princ (format "BEGIN:VEVENT %s -%s -SUMMARY:%s +%s%s +SUMMARY:%s%s%s CATEGORIES:%s END:VEVENT\n" - (org-ical-ts-to-string ts "DTSTART") - (org-ical-ts-to-string ts2 "DTEND" inc) - hd category))) + (org-ical-ts-to-string ts "DTSTART") + (org-ical-ts-to-string ts2 "DTEND" inc) + rrule summary + (if (and desc (string-match "\\S-" desc)) + (concat "\nDESCRIPTION: " desc) "") + (if (and location (string-match "\\S-" location)) + (concat "\nLOCATION: " location) "") + category))))) + + (when (and org-icalendar-include-sexps + (condition-case nil (require 'icalendar) (error nil)) + (fboundp 'icalendar-export-region)) + ;; Get all the literal sexps + (goto-char (point-min)) + (while (re-search-forward "^&?%%(" nil t) + (catch :skip + (org-agenda-skip) + (setq b (match-beginning 0)) + (goto-char (1- (match-end 0))) + (forward-sexp 1) + (end-of-line 1) + (setq sexp (buffer-substring b (point))) + (with-current-buffer sexp-buffer + (insert sexp "\n")) + (princ (org-diary-to-ical-string sexp-buffer))))) + (when org-icalendar-include-todo (goto-char (point-min)) (while (re-search-forward org-todo-line-regexp nil t) - (setq state (match-string 2)) - (setq status (if (equal state org-done-string) - "COMPLETED" "NEEDS-ACTION")) - (when (and state - (or (not (equal state org-done-string)) - (eq org-icalendar-include-todo 'all))) - (setq hd (match-string 3)) - (if (string-match org-priority-regexp hd) - (setq pri (string-to-char (match-string 2 hd)) - hd (concat (substring hd 0 (match-beginning 1)) - (substring hd (match-end 1)))) - (setq pri org-default-priority)) - (setq pri (floor (1+ (* 8. (/ (float (- org-lowest-priority pri)) - (- org-lowest-priority ?A)))))) + (catch :skip + (org-agenda-skip) + (when (boundp 'org-icalendar-verify-function) + (unless (funcall org-icalendar-verify-function) + (outline-next-heading) + (backward-char 1) + (throw :skip nil))) + (setq state (match-string 2)) + (setq status (if (member state org-done-keywords) + "COMPLETED" "NEEDS-ACTION")) + (when (and state + (or (not (member state org-done-keywords)) + (eq org-icalendar-include-todo 'all)) + (not (member org-archive-tag (org-get-tags-at))) + ) + (setq hd (match-string 3) + summary (org-icalendar-cleanup-string + (org-entry-get nil "SUMMARY")) + desc (org-icalendar-cleanup-string + (or (org-entry-get nil "DESCRIPTION") + (and org-icalendar-include-body (org-get-entry))) + t org-icalendar-include-body) + location (org-icalendar-cleanup-string + (org-entry-get nil "LOCATION"))) + (if (string-match org-bracket-link-regexp hd) + (setq hd (replace-match (if (match-end 3) (match-string 3 hd) + (match-string 1 hd)) + t t hd))) + (if (string-match org-priority-regexp hd) + (setq pri (string-to-char (match-string 2 hd)) + hd (concat (substring hd 0 (match-beginning 1)) + (substring hd (match-end 1)))) + (setq pri org-default-priority)) + (setq pri (floor (1+ (* 8. (/ (float (- org-lowest-priority pri)) + (- org-lowest-priority org-highest-priority)))))) - (princ (format "BEGIN:VTODO + (princ (format "BEGIN:VTODO %s -SUMMARY:%s +SUMMARY:%s%s%s CATEGORIES:%s SEQUENCE:1 PRIORITY:%d STATUS:%s END:VTODO\n" - dts hd category pri status)))))))) + dts + (or summary hd) + (if (and location (string-match "\\S-" location)) + (concat "\nLOCATION: " location) "") + (if (and desc (string-match "\\S-" desc)) + (concat "\nDESCRIPTION: " desc) "") + category pri status))))))))) + +(defun org-icalendar-cleanup-string (s &optional is-body maxlength) + "Take out stuff and quote what needs to be quoted. +When IS-BODY is non-nil, assume that this is the body of an item, clean up +whitespace, newlines, drawers, and timestamps, and cut it down to MAXLENGTH +characters." + (if (not s) + nil + (when is-body + (let ((re (concat "\\(" org-drawer-regexp "\\)[^\000]*?:END:.*\n?")) + (re2 (concat "^[ \t]*" org-keyword-time-regexp ".*\n?"))) + (while (string-match re s) (setq s (replace-match "" t t s))) + (while (string-match re2 s) (setq s (replace-match "" t t s))))) + (let ((start 0)) + (while (string-match "\\([,;\\]\\)" s start) + (setq start (+ (match-beginning 0) 2) + s (replace-match "\\\\\\1" nil nil s)))) + (when is-body + (while (string-match "[ \t]*\n[ \t]*" s) + (setq s (replace-match "\\n" t t s)))) + (setq s (org-trim s)) + (if is-body + (if maxlength + (if (and (numberp maxlength) + (> (length s) maxlength)) + (setq s (substring s 0 maxlength))))) + s)) + +(defun org-get-entry () + "Clean-up description string." + (save-excursion + (org-back-to-heading t) + (buffer-substring (point-at-bol 2) (org-end-of-subtree t)))) (defun org-start-icalendar-file (name) "Start an iCalendar file by inserting the header." @@ -18452,7 +26941,11 @@ a time), or the day by one (if it does not contain a time)." (let ((s (car t2)) (mi (nth 1 t2)) (h (nth 2 t2)) (d (nth 3 t2)) (m (nth 4 t2)) (y (nth 5 t2))) (when inc - (if have-time (setq h (+ 2 h)) (setq d (1+ d)))) + (if have-time + (if org-agenda-default-appointment-duration + (setq mi (+ org-agenda-default-appointment-duration mi)) + (setq h (+ 2 h))) + (setq d (1+ d)))) (setq time (encode-time s mi h d m y))) (setq fmt (if have-time ":%Y%m%dT%H%M%S" ";VALUE=DATE:%Y%m%d")) (concat keyword (format-time-string fmt time)))) @@ -18472,8 +26965,8 @@ The XOXO buffer is named *xoxo-*" ;; Output everything as XOXO (with-current-buffer (get-buffer buffer) - (goto-char (point-min)) ;; CD: beginning-of-buffer is not allowed. - (let* ((opt-plist (org-combine-plists (org-default-export-plist) + (let* ((pos (point)) + (opt-plist (org-combine-plists (org-default-export-plist) (org-infile-export-plist))) (filename (concat (file-name-as-directory (org-export-directory :xoxo opt-plist)) @@ -18483,11 +26976,12 @@ The XOXO buffer is named *xoxo-*" (out (find-file-noselect filename)) (last-level 1) (hanging-li nil)) + (goto-char (point-min)) ;; CD: beginning-of-buffer is not allowed. ;; Check the output buffer is empty. (with-current-buffer out (erase-buffer)) ;; Kick off the output (org-export-as-xoxo-insert-into out "
      \n") - (while (re-search-forward "^\\(\\*+\\) \\(.+\\)" (point-max) 't) + (while (re-search-forward "^\\(\\*+\\)[ \t]+\\(.+\\)" (point-max) 't) (let* ((hd (match-string-no-properties 1)) (level (length hd)) (text (concat @@ -18535,6 +27029,7 @@ The XOXO buffer is named *xoxo-*" (org-export-as-xoxo-insert-into out "\n")) (org-export-as-xoxo-insert-into out "
    \n")) + (goto-char pos) ;; Finish the buffer off and clean it up. (switch-to-buffer-other-window out) (indent-region (point-min) (point-max) nil) @@ -18545,47 +27040,44 @@ The XOXO buffer is named *xoxo-*" ;;;; Key bindings -;; - Bindings in Org-mode map are currently -;; 0123456789abcdefghijklmnopqrstuvwxyz!?@#$%^&-+*/=()_{}[]:;"|,.<>~`'\t the alphabet -;; abcd fgh j lmnopqrstuvwxyz!? #$ ^ -+*/= [] ; |,.<>~ '\t necessary bindings -;; e (?) useful from outline-mode -;; i k @ expendable from outline-mode -;; 0123456789 % & ()_{} " ` free - ;; Make `C-c C-x' a prefix key -(define-key org-mode-map "\C-c\C-x" (make-sparse-keymap)) +(org-defkey org-mode-map "\C-c\C-x" (make-sparse-keymap)) ;; TAB key with modifiers -(define-key org-mode-map "\C-i" 'org-cycle) -(define-key org-mode-map [(tab)] 'org-cycle) -(define-key org-mode-map [(control tab)] 'org-force-cycle-archived) -(define-key org-mode-map [(meta tab)] 'org-complete) -(define-key org-mode-map "\M-\t" 'org-complete) -(define-key org-mode-map "\M-\C-i" 'org-complete) +(org-defkey org-mode-map "\C-i" 'org-cycle) +(org-defkey org-mode-map [(tab)] 'org-cycle) +(org-defkey org-mode-map [(control tab)] 'org-force-cycle-archived) +(org-defkey org-mode-map [(meta tab)] 'org-complete) +(org-defkey org-mode-map "\M-\t" 'org-complete) +(org-defkey org-mode-map "\M-\C-i" 'org-complete) ;; The following line is necessary under Suse GNU/Linux (unless (featurep 'xemacs) - (define-key org-mode-map [S-iso-lefttab] 'org-shifttab)) -(define-key org-mode-map [(shift tab)] 'org-shifttab) + (org-defkey org-mode-map [S-iso-lefttab] 'org-shifttab)) +(org-defkey org-mode-map [(shift tab)] 'org-shifttab) +(define-key org-mode-map [backtab] 'org-shifttab) -(define-key org-mode-map (org-key 'S-return) 'org-table-copy-down) -(define-key org-mode-map [(meta shift return)] 'org-insert-todo-heading) -(define-key org-mode-map [(meta return)] 'org-meta-return) +(org-defkey org-mode-map [(shift return)] 'org-table-copy-down) +(org-defkey org-mode-map [(meta shift return)] 'org-insert-todo-heading) +(org-defkey org-mode-map [(meta return)] 'org-meta-return) ;; Cursor keys with modifiers -(define-key org-mode-map [(meta left)] 'org-metaleft) -(define-key org-mode-map [(meta right)] 'org-metaright) -(define-key org-mode-map [(meta up)] 'org-metaup) -(define-key org-mode-map [(meta down)] 'org-metadown) +(org-defkey org-mode-map [(meta left)] 'org-metaleft) +(org-defkey org-mode-map [(meta right)] 'org-metaright) +(org-defkey org-mode-map [(meta up)] 'org-metaup) +(org-defkey org-mode-map [(meta down)] 'org-metadown) -(define-key org-mode-map [(meta shift left)] 'org-shiftmetaleft) -(define-key org-mode-map [(meta shift right)] 'org-shiftmetaright) -(define-key org-mode-map [(meta shift up)] 'org-shiftmetaup) -(define-key org-mode-map [(meta shift down)] 'org-shiftmetadown) +(org-defkey org-mode-map [(meta shift left)] 'org-shiftmetaleft) +(org-defkey org-mode-map [(meta shift right)] 'org-shiftmetaright) +(org-defkey org-mode-map [(meta shift up)] 'org-shiftmetaup) +(org-defkey org-mode-map [(meta shift down)] 'org-shiftmetadown) -(define-key org-mode-map (org-key 'S-up) 'org-shiftup) -(define-key org-mode-map (org-key 'S-down) 'org-shiftdown) -(define-key org-mode-map (org-key 'S-left) 'org-shiftleft) -(define-key org-mode-map (org-key 'S-right) 'org-shiftright) +(org-defkey org-mode-map [(shift up)] 'org-shiftup) +(org-defkey org-mode-map [(shift down)] 'org-shiftdown) +(org-defkey org-mode-map [(shift left)] 'org-shiftleft) +(org-defkey org-mode-map [(shift right)] 'org-shiftright) + +(org-defkey org-mode-map [(control shift right)] 'org-shiftcontrolright) +(org-defkey org-mode-map [(control shift left)] 'org-shiftcontrolleft) ;;; Extra keys for tty access. ;; We only set them when really needed because otherwise the @@ -18593,102 +27085,115 @@ The XOXO buffer is named *xoxo-*" (when (or (featurep 'xemacs) ;; because XEmacs supports multi-device stuff (not window-system)) - (define-key org-mode-map "\C-c\C-xc" 'org-table-copy-down) - (define-key org-mode-map "\C-c\C-xM" 'org-insert-todo-heading) - (define-key org-mode-map "\C-c\C-xm" 'org-meta-return) - (define-key org-mode-map [?\e (return)] 'org-meta-return) - (define-key org-mode-map [?\e (left)] 'org-metaleft) - (define-key org-mode-map "\C-c\C-xl" 'org-metaleft) - (define-key org-mode-map [?\e (right)] 'org-metaright) - (define-key org-mode-map "\C-c\C-xr" 'org-metaright) - (define-key org-mode-map [?\e (up)] 'org-metaup) - (define-key org-mode-map "\C-c\C-xu" 'org-metaup) - (define-key org-mode-map [?\e (down)] 'org-metadown) - (define-key org-mode-map "\C-c\C-xd" 'org-metadown) - (define-key org-mode-map "\C-c\C-xL" 'org-shiftmetaleft) - (define-key org-mode-map "\C-c\C-xR" 'org-shiftmetaright) - (define-key org-mode-map "\C-c\C-xU" 'org-shiftmetaup) - (define-key org-mode-map "\C-c\C-xD" 'org-shiftmetadown) - (define-key org-mode-map [?\C-c ?\C-x (up)] 'org-shiftup) - (define-key org-mode-map [?\C-c ?\C-x (down)] 'org-shiftdown) - (define-key org-mode-map [?\C-c ?\C-x (left)] 'org-shiftleft) - (define-key org-mode-map [?\C-c ?\C-x (right)] 'org-shiftright)) + (org-defkey org-mode-map "\C-c\C-xc" 'org-table-copy-down) + (org-defkey org-mode-map "\C-c\C-xM" 'org-insert-todo-heading) + (org-defkey org-mode-map "\C-c\C-xm" 'org-meta-return) + (org-defkey org-mode-map [?\e (return)] 'org-meta-return) + (org-defkey org-mode-map [?\e (left)] 'org-metaleft) + (org-defkey org-mode-map "\C-c\C-xl" 'org-metaleft) + (org-defkey org-mode-map [?\e (right)] 'org-metaright) + (org-defkey org-mode-map "\C-c\C-xr" 'org-metaright) + (org-defkey org-mode-map [?\e (up)] 'org-metaup) + (org-defkey org-mode-map "\C-c\C-xu" 'org-metaup) + (org-defkey org-mode-map [?\e (down)] 'org-metadown) + (org-defkey org-mode-map "\C-c\C-xd" 'org-metadown) + (org-defkey org-mode-map "\C-c\C-xL" 'org-shiftmetaleft) + (org-defkey org-mode-map "\C-c\C-xR" 'org-shiftmetaright) + (org-defkey org-mode-map "\C-c\C-xU" 'org-shiftmetaup) + (org-defkey org-mode-map "\C-c\C-xD" 'org-shiftmetadown) + (org-defkey org-mode-map [?\C-c (up)] 'org-shiftup) + (org-defkey org-mode-map [?\C-c (down)] 'org-shiftdown) + (org-defkey org-mode-map [?\C-c (left)] 'org-shiftleft) + (org-defkey org-mode-map [?\C-c (right)] 'org-shiftright) + (org-defkey org-mode-map [?\C-c ?\C-x (right)] 'org-shiftcontrolright) + (org-defkey org-mode-map [?\C-c ?\C-x (left)] 'org-shiftcontrolleft)) ;; All the other keys -(define-key org-mode-map "\C-c\C-a" 'show-all) ; in case allout messed up. -(define-key org-mode-map "\C-c\C-r" 'org-reveal) -(define-key org-mode-map "\C-xns" 'org-narrow-to-subtree) -(define-key org-mode-map "\C-c$" 'org-archive-subtree) -(define-key org-mode-map "\C-c\C-x\C-s" 'org-advertized-archive-subtree) -(define-key org-mode-map "\C-c\C-x\C-a" 'org-toggle-archive-tag) -(define-key org-mode-map "\C-c\C-xb" 'org-tree-to-indirect-buffer) -(define-key org-mode-map "\C-c\C-j" 'org-goto) -(define-key org-mode-map "\C-c\C-t" 'org-todo) -(define-key org-mode-map "\C-c\C-s" 'org-schedule) -(define-key org-mode-map "\C-c\C-d" 'org-deadline) -(define-key org-mode-map "\C-c;" 'org-toggle-comment) -(define-key org-mode-map "\C-c\C-v" 'org-show-todo-tree) -(define-key org-mode-map "\C-c\C-w" 'org-check-deadlines) -(define-key org-mode-map "\C-c/" 'org-occur) ; Minor-mode reserved -(define-key org-mode-map "\C-c\\" 'org-tags-sparse-tree) ; Minor-mode res. -(define-key org-mode-map "\C-c\C-m" 'org-insert-heading) -(define-key org-mode-map "\M-\C-m" 'org-insert-heading) -(define-key org-mode-map "\C-c\C-x\C-n" 'org-next-link) -(define-key org-mode-map "\C-c\C-x\C-p" 'org-previous-link) -(define-key org-mode-map "\C-c\C-l" 'org-insert-link) -(define-key org-mode-map "\C-c\C-o" 'org-open-at-point) -(define-key org-mode-map "\C-c%" 'org-mark-ring-push) -(define-key org-mode-map "\C-c&" 'org-mark-ring-goto) -(define-key org-mode-map "\C-c\C-z" 'org-time-stamp) ; Alternative binding -(define-key org-mode-map "\C-c." 'org-time-stamp) ; Minor-mode reserved -(define-key org-mode-map "\C-c!" 'org-time-stamp-inactive) ; Minor-mode r. -(define-key org-mode-map "\C-c," 'org-priority) ; Minor-mode reserved -(define-key org-mode-map "\C-c\C-y" 'org-evaluate-time-range) -(define-key org-mode-map "\C-c>" 'org-goto-calendar) -(define-key org-mode-map "\C-c<" 'org-date-from-calendar) -(define-key org-mode-map [(control ?,)] 'org-cycle-agenda-files) -(define-key org-mode-map [(control ?\')] 'org-cycle-agenda-files) -(define-key org-mode-map "\C-c[" 'org-agenda-file-to-front) -(define-key org-mode-map "\C-c]" 'org-remove-file) -(define-key org-mode-map "\C-c-" 'org-table-insert-hline) -(define-key org-mode-map "\C-c^" 'org-sort) -(define-key org-mode-map "\C-c\C-c" 'org-ctrl-c-ctrl-c) -(define-key org-mode-map "\C-c#" 'org-update-checkbox-count) -(define-key org-mode-map "\C-m" 'org-return) -(define-key org-mode-map "\C-c?" 'org-table-field-info) -(define-key org-mode-map "\C-c " 'org-table-blank-field) -(define-key org-mode-map "\C-c+" 'org-table-sum) -(define-key org-mode-map "\C-c=" 'org-table-eval-formula) -(define-key org-mode-map "\C-c'" 'org-table-edit-formulas) -(define-key org-mode-map "\C-c`" 'org-table-edit-field) -(define-key org-mode-map "\C-c|" 'org-table-create-or-convert-from-region) -(define-key org-mode-map "\C-c*" 'org-table-recalculate) -(define-key org-mode-map [(control ?#)] 'org-table-rotate-recalc-marks) -(define-key org-mode-map "\C-c~" 'org-table-create-with-table.el) -(define-key org-mode-map "\C-c\C-q" 'org-table-wrap-region) -(define-key org-mode-map "\C-c}" 'org-table-toggle-coordinate-overlays) -(define-key org-mode-map "\C-c{" 'org-table-toggle-formula-debugger) -(define-key org-mode-map "\C-c\C-e" 'org-export) -(define-key org-mode-map "\C-c:" 'org-toggle-fixed-width-section) +(org-defkey org-mode-map "\C-c\C-a" 'show-all) ; in case allout messed up. +(org-defkey org-mode-map "\C-c\C-r" 'org-reveal) +(org-defkey org-mode-map "\C-xns" 'org-narrow-to-subtree) +(org-defkey org-mode-map "\C-c$" 'org-archive-subtree) +(org-defkey org-mode-map "\C-c\C-x\C-s" 'org-advertized-archive-subtree) +(org-defkey org-mode-map "\C-c\C-x\C-a" 'org-toggle-archive-tag) +(org-defkey org-mode-map "\C-c\C-xb" 'org-tree-to-indirect-buffer) +(org-defkey org-mode-map "\C-c\C-j" 'org-goto) +(org-defkey org-mode-map "\C-c\C-t" 'org-todo) +(org-defkey org-mode-map "\C-c\C-s" 'org-schedule) +(org-defkey org-mode-map "\C-c\C-d" 'org-deadline) +(org-defkey org-mode-map "\C-c;" 'org-toggle-comment) +(org-defkey org-mode-map "\C-c\C-v" 'org-show-todo-tree) +(org-defkey org-mode-map "\C-c\C-w" 'org-refile) +(org-defkey org-mode-map "\C-c/" 'org-sparse-tree) ; Minor-mode reserved +(org-defkey org-mode-map "\C-c\\" 'org-tags-sparse-tree) ; Minor-mode res. +(org-defkey org-mode-map "\C-c\C-m" 'org-ctrl-c-ret) +(org-defkey org-mode-map "\M-\C-m" 'org-insert-heading) +(org-defkey org-mode-map [(control return)] 'org-insert-heading-after-current) +(org-defkey org-mode-map "\C-c\C-x\C-n" 'org-next-link) +(org-defkey org-mode-map "\C-c\C-x\C-p" 'org-previous-link) +(org-defkey org-mode-map "\C-c\C-l" 'org-insert-link) +(org-defkey org-mode-map "\C-c\C-o" 'org-open-at-point) +(org-defkey org-mode-map "\C-c%" 'org-mark-ring-push) +(org-defkey org-mode-map "\C-c&" 'org-mark-ring-goto) +(org-defkey org-mode-map "\C-c\C-z" 'org-time-stamp) ; Alternative binding +(org-defkey org-mode-map "\C-c." 'org-time-stamp) ; Minor-mode reserved +(org-defkey org-mode-map "\C-c!" 'org-time-stamp-inactive) ; Minor-mode r. +(org-defkey org-mode-map "\C-c," 'org-priority) ; Minor-mode reserved +(org-defkey org-mode-map "\C-c\C-y" 'org-evaluate-time-range) +(org-defkey org-mode-map "\C-c>" 'org-goto-calendar) +(org-defkey org-mode-map "\C-c<" 'org-date-from-calendar) +(org-defkey org-mode-map [(control ?,)] 'org-cycle-agenda-files) +(org-defkey org-mode-map [(control ?\')] 'org-cycle-agenda-files) +(org-defkey org-mode-map "\C-c[" 'org-agenda-file-to-front) +(org-defkey org-mode-map "\C-c]" 'org-remove-file) +(org-defkey org-mode-map "\C-c\C-x<" 'org-agenda-set-restriction-lock) +(org-defkey org-mode-map "\C-c\C-x>" 'org-agenda-remove-restriction-lock) +(org-defkey org-mode-map "\C-c-" 'org-ctrl-c-minus) +(org-defkey org-mode-map "\C-c*" 'org-ctrl-c-star) +(org-defkey org-mode-map "\C-c^" 'org-sort) +(org-defkey org-mode-map "\C-c\C-c" 'org-ctrl-c-ctrl-c) +(org-defkey org-mode-map "\C-c\C-k" 'org-kill-note-or-show-branches) +(org-defkey org-mode-map "\C-c#" 'org-update-checkbox-count) +(org-defkey org-mode-map "\C-m" 'org-return) +(org-defkey org-mode-map "\C-j" 'org-return-indent) +(org-defkey org-mode-map "\C-c?" 'org-table-field-info) +(org-defkey org-mode-map "\C-c " 'org-table-blank-field) +(org-defkey org-mode-map "\C-c+" 'org-table-sum) +(org-defkey org-mode-map "\C-c=" 'org-table-eval-formula) +(org-defkey org-mode-map "\C-c'" 'org-table-edit-formulas) +(org-defkey org-mode-map "\C-c`" 'org-table-edit-field) +(org-defkey org-mode-map "\C-c|" 'org-table-create-or-convert-from-region) +(org-defkey org-mode-map [(control ?#)] 'org-table-rotate-recalc-marks) +(org-defkey org-mode-map "\C-c~" 'org-table-create-with-table.el) +(org-defkey org-mode-map "\C-c\C-q" 'org-table-wrap-region) +(org-defkey org-mode-map "\C-c}" 'org-table-toggle-coordinate-overlays) +(org-defkey org-mode-map "\C-c{" 'org-table-toggle-formula-debugger) +(org-defkey org-mode-map "\C-c\C-e" 'org-export) +(org-defkey org-mode-map "\C-c:" 'org-toggle-fixed-width-section) +(org-defkey org-mode-map "\C-c\C-x\C-f" 'org-emphasize) -(define-key org-mode-map "\C-c\C-x\C-k" 'org-cut-special) -(define-key org-mode-map "\C-c\C-x\C-w" 'org-cut-special) -(define-key org-mode-map "\C-c\C-x\M-w" 'org-copy-special) -(define-key org-mode-map "\C-c\C-x\C-y" 'org-paste-special) +(org-defkey org-mode-map "\C-c\C-x\C-k" 'org-cut-special) +(org-defkey org-mode-map "\C-c\C-x\C-w" 'org-cut-special) +(org-defkey org-mode-map "\C-c\C-x\M-w" 'org-copy-special) +(org-defkey org-mode-map "\C-c\C-x\C-y" 'org-paste-special) -(define-key org-mode-map "\C-c\C-x\C-t" 'org-toggle-time-stamp-overlays) -(define-key org-mode-map "\C-c\C-x\C-i" 'org-clock-in) -(define-key org-mode-map "\C-c\C-x\C-o" 'org-clock-out) -(define-key org-mode-map "\C-c\C-x\C-x" 'org-clock-cancel) -(define-key org-mode-map "\C-c\C-x\C-d" 'org-clock-display) -(define-key org-mode-map "\C-c\C-x\C-r" 'org-clock-report) -(define-key org-mode-map "\C-c\C-x\C-u" 'org-dblock-update) -(define-key org-mode-map "\C-c\C-x\C-l" 'org-preview-latex-fragment) -(define-key org-mode-map "\C-c\C-x\C-b" 'org-toggle-checkbox) +(org-defkey org-mode-map "\C-c\C-x\C-t" 'org-toggle-time-stamp-overlays) +(org-defkey org-mode-map "\C-c\C-x\C-i" 'org-clock-in) +(org-defkey org-mode-map "\C-c\C-x\C-o" 'org-clock-out) +(org-defkey org-mode-map "\C-c\C-x\C-j" 'org-clock-goto) +(org-defkey org-mode-map "\C-c\C-x\C-x" 'org-clock-cancel) +(org-defkey org-mode-map "\C-c\C-x\C-d" 'org-clock-display) +(org-defkey org-mode-map "\C-c\C-x\C-r" 'org-clock-report) +(org-defkey org-mode-map "\C-c\C-x\C-u" 'org-dblock-update) +(org-defkey org-mode-map "\C-c\C-x\C-l" 'org-preview-latex-fragment) +(org-defkey org-mode-map "\C-c\C-x\C-b" 'org-toggle-checkbox) +(org-defkey org-mode-map "\C-c\C-xp" 'org-set-property) +(org-defkey org-mode-map "\C-c\C-xr" 'org-insert-columns-dblock) + +(define-key org-mode-map "\C-c\C-x\C-c" 'org-columns) (when (featurep 'xemacs) - (define-key org-mode-map 'button3 'popup-mode-menu)) + (org-defkey org-mode-map 'button3 'popup-mode-menu)) (defsubst org-table-p () (org-at-table-p)) @@ -18717,7 +27222,13 @@ overwritten, and the table is not marked as requiring realignment." (goto-char (match-beginning 0)) (self-insert-command N)) (setq org-table-may-need-update t) - (self-insert-command N))) + (self-insert-command N) + (org-fix-tags-on-the-fly))) + +(defun org-fix-tags-on-the-fly () + (when (and (equal (char-after (point-at-bol)) ?*) + (org-on-heading-p)) + (org-align-tags-here org-tags-column))) (defun org-delete-backward-char (N) "Like `delete-backward-char', insert whitespace at field end in tables. @@ -18740,7 +27251,8 @@ because, in this case the deletion might narrow the column." ;; noalign: if there were two spaces at the end, this field ;; does not determine the width of the column. (if noalign (setq org-table-may-need-update c))) - (backward-delete-char N))) + (backward-delete-char N) + (org-fix-tags-on-the-fly))) (defun org-delete-char (N) "Like `delete-char', but insert whitespace at field end in tables. @@ -18765,7 +27277,8 @@ because, in this case the deletion might narrow the column." ;; does not determine the width of the column. (if noalign (setq org-table-may-need-update c))) (delete-char N)) - (delete-char N))) + (delete-char N) + (org-fix-tags-on-the-fly))) ;; Make `delete-selection-mode' work with org-mode and orgtbl-mode (put 'org-self-insert-command 'delete-selection t) @@ -18779,6 +27292,9 @@ because, in this case the deletion might narrow the column." (put 'org-delete-char 'flyspell-delayed t) (put 'org-delete-backward-char 'flyspell-delayed t) +;; Make pabbrev-mode expand after org-mode commands +(put 'org-self-insert-command 'pabbrev-expand-after-command t) +(put 'orgybl-self-insert-command 'pabbrev-expand-after-command t) ;; How to do this: Measure non-white length of current string ;; If equal to column width, we should realign. @@ -18790,7 +27306,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names." (while commands (setq old (pop commands) new (pop commands)) (if (fboundp 'command-remapping) - (define-key map (vector 'remap old) new) + (org-defkey map (vector 'remap old) new) (substitute-key-definition old new map global-map))))) (when (eq org-enable-table-editor 'optimized) @@ -18800,7 +27316,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names." 'self-insert-command 'org-self-insert-command 'delete-char 'org-delete-char 'delete-backward-char 'org-delete-backward-char) - (define-key org-mode-map "|" 'org-force-self-insert)) + (org-defkey org-mode-map "|" 'org-force-self-insert)) (defun org-shiftcursor-error () "Throw an error because Shift-Cursor command was applied in wrong context." @@ -18821,7 +27337,8 @@ See the individual commands for more information." (defun org-shiftmetaleft () "Promote subtree or delete table column. -Calls `org-promote-subtree' or `org-table-delete-column', depending on context. +Calls `org-promote-subtree', `org-outdent-item', +or `org-table-delete-column', depending on context. See the individual commands for more information." (interactive) (cond @@ -18832,7 +27349,8 @@ See the individual commands for more information." (defun org-shiftmetaright () "Demote subtree or insert table column. -Calls `org-demote-subtree' or `org-table-insert-column', depending on context. +Calls `org-demote-subtree', `org-indent-item', +or `org-table-insert-column', depending on context. See the individual commands for more information." (interactive) (cond @@ -18900,7 +27418,7 @@ for more information." ((org-at-table-p) (org-call-with-arg 'org-table-move-row 'up)) ((org-on-heading-p) (call-interactively 'org-move-subtree-up)) ((org-at-item-p) (call-interactively 'org-move-item-up)) - (t (org-shiftcursor-error)))) + (t (transpose-lines 1) (beginning-of-line -1)))) (defun org-metadown (&optional arg) "Move subtree down or move table row down. @@ -18912,26 +27430,30 @@ commands for more information." ((org-at-table-p) (call-interactively 'org-table-move-row)) ((org-on-heading-p) (call-interactively 'org-move-subtree-down)) ((org-at-item-p) (call-interactively 'org-move-item-down)) - (t (org-shiftcursor-error)))) + (t (beginning-of-line 2) (transpose-lines 1) (beginning-of-line 0)))) (defun org-shiftup (&optional arg) "Increase item in timestamp or increase priority of current headline. -Calls `org-timestamp-up' or `org-priority-up', depending on context. -See the individual commands for more information." +Calls `org-timestamp-up' or `org-priority-up', or `org-previous-item', +depending on context. See the individual commands for more information." (interactive "P") (cond - ((org-at-timestamp-p t) (call-interactively 'org-timestamp-up)) + ((org-at-timestamp-p t) + (call-interactively (if org-edit-timestamp-down-means-later + 'org-timestamp-down 'org-timestamp-up))) ((org-on-heading-p) (call-interactively 'org-priority-up)) ((org-at-item-p) (call-interactively 'org-previous-item)) (t (call-interactively 'org-beginning-of-item) (beginning-of-line 1)))) (defun org-shiftdown (&optional arg) "Decrease item in timestamp or decrease priority of current headline. -Calls `org-timestamp-down' or `org-priority-down', depending on context. -See the individual commands for more information." +Calls `org-timestamp-down' or `org-priority-down', or `org-next-item' +depending on context. See the individual commands for more information." (interactive "P") (cond - ((org-at-timestamp-p t) (call-interactively 'org-timestamp-down)) + ((org-at-timestamp-p t) + (call-interactively (if org-edit-timestamp-down-means-later + 'org-timestamp-up 'org-timestamp-down))) ((org-on-heading-p) (call-interactively 'org-priority-down)) (t (call-interactively 'org-next-item)))) @@ -18941,6 +27463,8 @@ See the individual commands for more information." (cond ((org-at-timestamp-p t) (call-interactively 'org-timestamp-up-day)) ((org-on-heading-p) (org-call-with-arg 'org-todo 'right)) + ((org-at-item-p) (org-call-with-arg 'org-cycle-list-bullet nil)) + ((org-at-property-p) (call-interactively 'org-property-next-allowed-value)) (t (org-shiftcursor-error)))) (defun org-shiftleft () @@ -18949,8 +27473,32 @@ See the individual commands for more information." (cond ((org-at-timestamp-p t) (call-interactively 'org-timestamp-down-day)) ((org-on-heading-p) (org-call-with-arg 'org-todo 'left)) + ((org-at-item-p) (org-call-with-arg 'org-cycle-list-bullet 'previous)) + ((org-at-property-p) + (call-interactively 'org-property-previous-allowed-value)) (t (org-shiftcursor-error)))) +(defun org-shiftcontrolright () + "Switch to next TODO set." + (interactive) + (cond + ((org-on-heading-p) (org-call-with-arg 'org-todo 'nextset)) + (t (org-shiftcursor-error)))) + +(defun org-shiftcontrolleft () + "Switch to previous TODO set." + (interactive) + (cond + ((org-on-heading-p) (org-call-with-arg 'org-todo 'previousset)) + (t (org-shiftcursor-error)))) + +(defun org-ctrl-c-ret () + "Call `org-table-hline-and-move' or `org-insert-heading' dep. on context." + (interactive) + (cond + ((org-at-table-p) (call-interactively 'org-table-hline-and-move)) + (t (call-interactively 'org-insert-heading)))) + (defun org-copy-special () "Copy region in table or copy current subtree. Calls `org-table-copy' or `org-copy-subtree', depending on context. @@ -18995,6 +27543,8 @@ This command does many different things, depending on context: - If the cursor is on a #+TBLFM line, re-apply the formulas to the entire table. +- If the cursor is a the beginning of a dynamic block, update it. + - If the cursor is inside a table created by the table.el package, activate that table. @@ -19006,7 +27556,9 @@ This command does many different things, depending on context: links in this buffer. - If the cursor is on a numbered item in a plain list, renumber the - ordered list." + ordered list. + +- If the cursor is on a checkbox, toggle it." (interactive "P") (let ((org-enable-table-editor t)) (cond @@ -19020,6 +27572,8 @@ This command does many different things, depending on context: ((and (local-variable-p 'org-finish-function (current-buffer)) (fboundp org-finish-function)) (funcall org-finish-function)) + ((org-at-property-p) + (call-interactively 'org-property-action)) ((org-on-target-p) (call-interactively 'org-update-radio-target-regexp)) ((org-on-heading-p) (call-interactively 'org-set-tags)) ((org-at-table.el-p) @@ -19036,7 +27590,11 @@ This command does many different things, depending on context: ((org-at-item-checkbox-p) (call-interactively 'org-toggle-checkbox)) ((org-at-item-p) - (call-interactively 'org-renumber-ordered-list)) + (call-interactively 'org-maybe-renumber-ordered-list)) + ((save-excursion (beginning-of-line 1) (looking-at "#\\+BEGIN:")) + ;; Dynamic block + (beginning-of-line 1) + (org-update-dblock)) ((save-excursion (beginning-of-line 1) (looking-at "#\\+\\([A-Z]+\\)")) (cond ((equal (match-string 1) "TBLFM") @@ -19057,16 +27615,145 @@ Also updates the keyword regular expressions." (let ((org-inhibit-startup t)) (org-mode)) (message "Org-mode restarted to refresh keyword and special line setup")) -(defun org-return () +(defun org-kill-note-or-show-branches () + "If this is a Note buffer, abort storing the note. Else call `show-branches'." + (interactive) + (if (not org-finish-function) + (call-interactively 'show-branches) + (let ((org-note-abort t)) + (funcall org-finish-function)))) + +(defun org-return (&optional indent) "Goto next table row or insert a newline. Calls `org-table-next-row' or `newline', depending on context. See the individual commands for more information." (interactive) (cond + ((bobp) (if indent (newline-and-indent) (newline))) + ((and (org-at-heading-p) + (looking-at + (org-re "\\([ \t]+\\(:[[:alnum:]_@:]+:\\)\\)[ \t]*$"))) + (org-show-entry) + (end-of-line 1) + (newline)) ((org-at-table-p) (org-table-justify-field-maybe) (call-interactively 'org-table-next-row)) - (t (newline)))) + (t (if indent (newline-and-indent) (newline))))) + +(defun org-return-indent () + "Goto next table row or insert a newline and indent. +Calls `org-table-next-row' or `newline-and-indent', depending on +context. See the individual commands for more information." + (interactive) + (org-return t)) + +(defun org-ctrl-c-star () + "Compute table, or change heading status of lines. +Calls `org-table-recalculate' or `org-toggle-region-headlines', +depending on context. This will also turn a plain list item or a normal +line into a subheading." + (interactive) + (cond + ((org-at-table-p) + (call-interactively 'org-table-recalculate)) + ((org-region-active-p) + ;; Convert all lines in region to list items + (call-interactively 'org-toggle-region-headings)) + ((org-on-heading-p) + (org-toggle-region-headings (point-at-bol) + (min (1+ (point-at-eol)) (point-max)))) + ((org-at-item-p) + ;; Convert to heading + (let ((level (save-match-data + (save-excursion + (condition-case nil + (progn + (org-back-to-heading t) + (funcall outline-level)) + (error 0)))))) + (replace-match + (concat (make-string (org-get-valid-level level 1) ?*) " ") t t))) + (t (org-toggle-region-headings (point-at-bol) + (min (1+ (point-at-eol)) (point-max)))))) + +(defun org-ctrl-c-minus () + "Insert separator line in table or modify bullet status of line. +Also turns a plain line or a region of lines into list items. +Calls `org-table-insert-hline', `org-toggle-region-items', or +`org-cycle-list-bullet', depending on context." + (interactive) + (cond + ((org-at-table-p) + (call-interactively 'org-table-insert-hline)) + ((org-on-heading-p) + ;; Convert to item + (save-excursion + (beginning-of-line 1) + (if (looking-at "\\*+ ") + (replace-match (concat (make-string (- (match-end 0) (point) 1) ?\ ) "- "))))) + ((org-region-active-p) + ;; Convert all lines in region to list items + (call-interactively 'org-toggle-region-items)) + ((org-in-item-p) + (call-interactively 'org-cycle-list-bullet)) + (t (org-toggle-region-items (point-at-bol) + (min (1+ (point-at-eol)) (point-max)))))) + +(defun org-toggle-region-items (beg end) + "Convert all lines in region to list items. +If the first line is already an item, convert all list items in the region +to normal lines." + (interactive "r") + (let (l2 l) + (save-excursion + (goto-char end) + (setq l2 (org-current-line)) + (goto-char beg) + (beginning-of-line 1) + (setq l (1- (org-current-line))) + (if (org-at-item-p) + ;; We already have items, de-itemize + (while (< (setq l (1+ l)) l2) + (when (org-at-item-p) + (goto-char (match-beginning 2)) + (delete-region (match-beginning 2) (match-end 2)) + (and (looking-at "[ \t]+") (replace-match ""))) + (beginning-of-line 2)) + (while (< (setq l (1+ l)) l2) + (unless (org-at-item-p) + (if (looking-at "\\([ \t]*\\)\\(\\S-\\)") + (replace-match "\\1- \\2"))) + (beginning-of-line 2)))))) + +(defun org-toggle-region-headings (beg end) + "Convert all lines in region to list items. +If the first line is already an item, convert all list items in the region +to normal lines." + (interactive "r") + (let (l2 l) + (save-excursion + (goto-char end) + (setq l2 (org-current-line)) + (goto-char beg) + (beginning-of-line 1) + (setq l (1- (org-current-line))) + (if (org-on-heading-p) + ;; We already have headlines, de-star them + (while (< (setq l (1+ l)) l2) + (when (org-on-heading-p t) + (and (looking-at outline-regexp) (replace-match ""))) + (beginning-of-line 2)) + (let* ((stars (save-excursion + (re-search-backward org-complex-heading-regexp nil t) + (or (match-string 1) "*"))) + (add-stars (if org-odd-levels-only "**" "*")) + (rpl (concat stars add-stars " \\2"))) + (while (< (setq l (1+ l)) l2) + (unless (org-on-heading-p) + (if (looking-at "\\([ \t]*\\)\\(\\S-\\)") + (replace-match rpl))) + (beginning-of-line 2))))))) (defun org-meta-return (&optional arg) "Insert a new heading or wrap a region in a table. @@ -19104,7 +27791,7 @@ See the individual commands for more information." ["Insert Row" org-shiftmetadown (org-at-table-p)] ["Sort lines in region" org-table-sort-lines (org-at-table-p)] "--" - ["Insert Hline" org-table-insert-hline (org-at-table-p)]) + ["Insert Hline" org-ctrl-c-minus (org-at-table-p)]) ("Rectangle" ["Copy Rectangle" org-copy-special (org-at-table-p)] ["Cut Rectangle" org-cut-special (org-at-table-p)] @@ -19177,6 +27864,8 @@ See the individual commands for more information." "--" ["Convert to odd levels" org-convert-to-odd-levels t] ["Convert to odd/even levels" org-convert-to-oddeven-levels t]) + ("Editing" + ["Emphasis..." org-emphasize t]) ("Archive" ["Toggle ARCHIVE tag" org-toggle-archive-tag t] ; ["Check and Tag Children" (org-toggle-archive-tag (4)) @@ -19202,22 +27891,22 @@ See the individual commands for more information." ("Select keyword" ["Next keyword" org-shiftright (org-on-heading-p)] ["Previous keyword" org-shiftleft (org-on-heading-p)] - ["Complete Keyword" org-complete (assq :todo-keyword (org-context))]) + ["Complete Keyword" org-complete (assq :todo-keyword (org-context))] + ["Next keyword set" org-shiftcontrolright (and (> (length org-todo-sets) 1) (org-on-heading-p))] + ["Previous keyword set" org-shiftcontrolright (and (> (length org-todo-sets) 1) (org-on-heading-p))]) ["Show TODO Tree" org-show-todo-tree t] ["Global TODO list" org-todo-list t] "--" ["Set Priority" org-priority t] ["Priority Up" org-shiftup t] - ["Priority Down" org-shiftdown t] + ["Priority Down" org-shiftdown t]) + ("TAGS and Properties" + ["Set Tags" 'org-ctrl-c-ctrl-c (org-at-heading-p)] + ["Change tag in region" 'org-change-tag-in-region (org-region-active-p)] "--" -; ["Insert Checkbox" org-insert-todo-heading (org-in-item-p)] -; ["Toggle Checkbox" org-ctrl-c-ctrl-c (org-at-item-checkbox-p)] -; ["Insert [n/m] cookie" (progn (insert "[/]") (org-update-checkbox-count)) -; (or (org-on-heading-p) (org-at-item-p))] -; ["Insert [%] cookie" (progn (insert "[%]") (org-update-checkbox-count)) -; (or (org-on-heading-p) (org-at-item-p))] -; ["Update Statistics" org-update-checkbox-count t] - ) + ["Set property" 'org-set-property t] + ["Column view of properties" org-columns t] + ["Insert Column View DBlock" org-insert-columns-dblock t]) ("Dates and Scheduling" ["Timestamp" org-time-stamp t] ["Timestamp (inactive)" org-time-stamp-inactive t] @@ -19239,17 +27928,19 @@ See the individual commands for more information." ["Clock in" org-clock-in t] ["Clock out" org-clock-out t] ["Clock cancel" org-clock-cancel t] + ["Goto running clock" org-clock-goto t] ["Display times" org-clock-display t] ["Create clock table" org-clock-report t] "--" ["Record DONE time" (progn (setq org-log-done (not org-log-done)) (message "Switching to %s will %s record a timestamp" - org-done-string + (car org-done-keywords) (if org-log-done "automatically" "not"))) :style toggle :selected org-log-done]) "--" ["Agenda Command..." org-agenda t] + ["Set Restriction Lock" org-agenda-set-restriction-lock t] ("File List for Agenda") ("Special views current file" ["TODO Tree" org-show-todo-tree t] @@ -19297,21 +27988,11 @@ See the individual commands for more information." ["Refresh setup" org-mode-restart t] )) -(defun org-toggle-log-option (type) - (if (not (listp org-log-done)) (setq org-log-done nil)) - (if (memq type org-log-done) - (setq org-log-done (delq type org-log-done)) - (add-to-list 'org-log-done type))) - -(defun org-check-log-option (type) - (and (listp org-log-done) (memq type org-log-done))) - (defun org-info (&optional node) "Read documentation for Org-mode in the info system. With optional NODE, go directly to that node." (interactive) - (require 'info) - (Info-goto-node (format "(org)%s" (or node "")))) + (info (format "(org)%s" (or node "")))) (defun org-install-agenda-files-menu () (let ((bl (buffer-list))) @@ -19328,6 +28009,7 @@ With optional NODE, go directly to that node." ["Add/Move Current File to Front of List" org-agenda-file-to-front t] ["Remove Current File from List" org-remove-file t] ["Cycle through agenda files" org-cycle-agenda-files t] + ["Occur in all agenda files" org-occur-in-agenda-files t] "--") (mapcar 'org-file-menu-entry (org-agenda-files t)))))))) @@ -19394,7 +28076,7 @@ and :keyword." (p (point)) clist o) ;; First the large context (cond - ((org-on-heading-p) + ((org-on-heading-p t) (push (list :headline (point-at-bol) (point-at-eol)) clist) (when (progn (beginning-of-line 1) @@ -19404,7 +28086,7 @@ and :keyword." (push (org-point-in-group p 4 :tags) clist)) (goto-char p) (skip-chars-backward "^[\n\r \t") (or (eobp) (backward-char 1)) - (if (looking-at "\\[#[A-Z]\\]") + (if (looking-at "\\[#[A-Z0-9]\\]") (push (org-point-in-group p 0 :priority) clist))) ((org-at-item-p) @@ -19459,6 +28141,7 @@ and :keyword." (setq clist (nreverse (delq nil clist))) clist)) +;; FIXME: Compare with at-regexp-p Do we need both? (defun org-in-regexp (re &optional nlines visually) "Check if point is inside a match of regexp. Normally only the current line is checked, but you can include NLINES extra @@ -19476,6 +28159,79 @@ really on, so that the block visually is on the match." (>= (+ inc (match-end 0)) pos)) (throw 'exit (cons (match-beginning 0) (match-end 0))))))))) +(defun org-at-regexp-p (regexp) + "Is point inside a match of REGEXP in the current line?" + (catch 'exit + (save-excursion + (let ((pos (point)) (end (point-at-eol))) + (beginning-of-line 1) + (while (re-search-forward regexp end t) + (if (and (<= (match-beginning 0) pos) + (>= (match-end 0) pos)) + (throw 'exit t))) + nil)))) + +(defun org-occur-in-agenda-files (regexp &optional nlines) + "Call `multi-occur' with buffers for all agenda files." + (interactive "sOrg-files matching: \np") + (let* ((files (org-agenda-files)) + (tnames (mapcar 'file-truename files)) + (extra org-agenda-text-search-extra-files) + f) + (while (setq f (pop extra)) + (unless (member (file-truename f) tnames) + (add-to-list 'files f 'append) + (add-to-list 'tnames (file-truename f) 'append))) + (multi-occur + (mapcar (lambda (x) (or (get-file-buffer x) (find-file-noselect x))) files) + regexp))) + +(if (boundp 'occur-mode-find-occurrence-hook) + ;; Emacs 23 + (add-hook 'occur-mode-find-occurrence-hook + (lambda () + (when (org-mode-p) + (org-reveal)))) + ;; Emacs 22 + (defadvice occur-mode-goto-occurrence + (after org-occur-reveal activate) + (and (org-mode-p) (org-reveal))) + (defadvice occur-mode-goto-occurrence-other-window + (after org-occur-reveal activate) + (and (org-mode-p) (org-reveal))) + (defadvice occur-mode-display-occurrence + (after org-occur-reveal activate) + (when (org-mode-p) + (let ((pos (occur-mode-find-occurrence))) + (with-current-buffer (marker-buffer pos) + (save-excursion + (goto-char pos) + (org-reveal))))))) + +(defun org-uniquify (list) + "Remove duplicate elements from LIST." + (let (res) + (mapc (lambda (x) (add-to-list 'res x 'append)) list) + res)) + +(defun org-delete-all (elts list) + "Remove all elements in ELTS from LIST." + (while elts + (setq list (delete (pop elts) list))) + list) + +(defun org-back-over-empty-lines () + "Move backwards over witespace, to the beginning of the first empty line. +Returns the number of empty lines passed." + (let ((pos (point))) + (skip-chars-backward " \t\n\r") + (beginning-of-line 2) + (goto-char (min (point) pos)) + (count-lines (point) pos))) + +(defun org-skip-whitespace () + (skip-chars-forward " \t\n\r")) + (defun org-point-in-group (point group &optional context) "Check if POINT is in match-group GROUP. If CONTEXT is non-nil, return a list with CONTEXT and the boundaries of the @@ -19488,6 +28244,13 @@ return nil." (list context (match-beginning group) (match-end group)) t))) +(defun org-switch-to-buffer-other-window (&rest args) + "Switch to buffer in a second window on the current frame. +In particular, do not allow pop-up frames." + (let (pop-up-frames special-display-buffer-names special-display-regexps + special-display-function) + (apply 'switch-to-buffer-other-window args))) + (defun org-combine-plists (&rest plists) "Create a single property list from all plists in PLISTS. The process starts by copying the first list, and then setting properties @@ -19530,7 +28293,7 @@ ones and overrule settings in the other lists." (defun org-replace-escapes (string table) "Replace %-escapes in STRING with values in TABLE. -TABLE is an association list with keys line \"%a\" and string values. +TABLE is an association list with keys like \"%a\" and string values. The sequences in STRING may contain normal field width and padding information, for example \"%-5s\". Replacements happen in the sequence given by TABLE, so values can contain further %-escapes if they are define later in TABLE." @@ -19555,82 +28318,13 @@ Counting starts at 1." (setq c (1+ c))) (nreverse rtn))) -(defun org-at-regexp-p (regexp) - "Is point inside a match of REGEXP in the current line?" - (catch 'exit - (save-excursion - (let ((pos (point)) (end (point-at-eol))) - (beginning-of-line 1) - (while (re-search-forward regexp end t) - (if (and (<= (match-beginning 0) pos) - (>= (match-end 0) pos)) - (throw 'exit t))) - nil)))) - (defun org-find-base-buffer-visiting (file) "Like `find-buffer-visiting' but alway return the base buffer and -not an indirect buffer" +not an indirect buffer." (let ((buf (find-buffer-visiting file))) - (or (buffer-base-buffer buf) buf))) - -;;; Paragraph filling stuff. -;; We want this to be just right, so use the full arsenal. -;; FIXME: configure filladapt for XEmacs - -(defun org-set-autofill-regexps () - (interactive) - ;; In the paragraph separator we include headlines, because filling - ;; text in a line directly attached to a headline would otherwise - ;; fill the headline as well. - (org-set-local 'comment-start-skip "^#+[ \t]*") - (org-set-local 'paragraph-separate "\f\\|\\*\\|[ ]*$\\|[ \t]*[:|]") - ;; The paragraph starter includes hand-formatted lists. - (org-set-local 'paragraph-start - "\f\\|[ ]*$\\|\\([*\f]+\\)\\|[ \t]*\\([-+*][ \t]+\\|[0-9]+[.)][ \t]+\\)\\|[ \t]*[:|]") - ;; Inhibit auto-fill for headers, tables and fixed-width lines. - ;; But only if the user has not turned off tables or fixed-width regions - (org-set-local - 'auto-fill-inhibit-regexp - (concat "\\*\\|#\\+" - "\\|[ \t]*" org-keyword-time-regexp - (if (or org-enable-table-editor org-enable-fixed-width-editor) - (concat - "\\|[ \t]*[" - (if org-enable-table-editor "|" "") - (if org-enable-fixed-width-editor ":" "") - "]")))) - ;; We use our own fill-paragraph function, to make sure that tables - ;; and fixed-width regions are not wrapped. That function will pass - ;; through to `fill-paragraph' when appropriate. - (org-set-local 'fill-paragraph-function 'org-fill-paragraph) - ; Adaptive filling: To get full control, first make sure that - ;; `adaptive-fill-regexp' never matches. Then install our own matcher. - (org-set-local 'adaptive-fill-regexp "\000") - (org-set-local 'adaptive-fill-function - 'org-adaptive-fill-function)) - -(defun org-fill-paragraph (&optional justify) - "Re-align a table, pass through to fill-paragraph if no table." - (let ((table-p (org-at-table-p)) - (table.el-p (org-at-table.el-p))) - (cond ((equal (char-after (point-at-bol)) ?*) t) ; skip headlines - (table.el-p t) ; skip table.el tables - (table-p (org-table-align) t) ; align org-mode tables - (t nil)))) ; call paragraph-fill - -;; For reference, this is the default value of adaptive-fill-regexp -;; "[ \t]*\\([-|#;>*]+[ \t]*\\|(?[0-9]+[.)][ \t]*\\)*" - -(defun org-adaptive-fill-function () - "Return a fill prefix for org-mode files. -In particular, this makes sure hanging paragraphs for hand-formatted lists -work correctly." - (cond ((looking-at "#[ \t]+") - (match-string 0)) - ((looking-at " *\\([-*+] \\|[0-9]+[.)] \\)?") - (make-string (- (match-end 0) (match-beginning 0)) ?\ )) - (t nil))) - + (if buf + (or (buffer-base-buffer buf) buf) + nil))) (defun org-image-file-name-regexp () "Return regexp matching the file names of images." @@ -19651,25 +28345,207 @@ work correctly." (save-match-data (string-match (org-image-file-name-regexp) file))) +;;; Paragraph filling stuff. +;; We want this to be just right, so use the full arsenal. + +(defun org-indent-line-function () + "Indent line like previous, but further if previous was headline or item." + (interactive) + (let* ((pos (point)) + (itemp (org-at-item-p)) + column bpos bcol tpos tcol bullet btype bullet-type) + ;; Find the previous relevant line + (beginning-of-line 1) + (cond + ((looking-at "#") (setq column 0)) + ((looking-at "\\*+ ") (setq column 0)) + (t + (beginning-of-line 0) + (while (and (not (bobp)) (looking-at "[ \t]*[\n:#|]")) + (beginning-of-line 0)) + (cond + ((looking-at "\\*+[ \t]+") + (goto-char (match-end 0)) + (setq column (current-column))) + ((org-in-item-p) + (org-beginning-of-item) +; (looking-at "[ \t]*\\(\\S-+\\)[ \t]*") + (looking-at "[ \t]*\\(\\S-+\\)[ \t]*\\(\\[[- X]\\][ \t]*\\)?") + (setq bpos (match-beginning 1) tpos (match-end 0) + bcol (progn (goto-char bpos) (current-column)) + tcol (progn (goto-char tpos) (current-column)) + bullet (match-string 1) + bullet-type (if (string-match "[0-9]" bullet) "n" bullet)) + (if (not itemp) + (setq column tcol) + (goto-char pos) + (beginning-of-line 1) + (if (looking-at "\\S-") + (progn + (looking-at "[ \t]*\\(\\S-+\\)[ \t]*") + (setq bullet (match-string 1) + btype (if (string-match "[0-9]" bullet) "n" bullet)) + (setq column (if (equal btype bullet-type) bcol tcol))) + (setq column (org-get-indentation))))) + (t (setq column (org-get-indentation)))))) + (goto-char pos) + (if (<= (current-column) (current-indentation)) + (indent-line-to column) + (save-excursion (indent-line-to column))) + (setq column (current-column)) + (beginning-of-line 1) + (if (looking-at + "\\([ \t]+\\)\\(:[-_0-9a-zA-Z]+:\\)[ \t]*\\(\\S-.*\\(\\S-\\|$\\)\\)") + (replace-match (concat "\\1" (format org-property-format + (match-string 2) (match-string 3))) + t nil)) + (move-to-column column))) + +(defun org-set-autofill-regexps () + (interactive) + ;; In the paragraph separator we include headlines, because filling + ;; text in a line directly attached to a headline would otherwise + ;; fill the headline as well. + (org-set-local 'comment-start-skip "^#+[ \t]*") + (org-set-local 'paragraph-separate "\f\\|\\*+ \\|[ ]*$\\|[ \t]*[:|]") + ;; The paragraph starter includes hand-formatted lists. + (org-set-local 'paragraph-start + "\f\\|[ ]*$\\|\\*+ \\|\f\\|[ \t]*\\([-+*][ \t]+\\|[0-9]+[.)][ \t]+\\)\\|[ \t]*[:|]") + ;; Inhibit auto-fill for headers, tables and fixed-width lines. + ;; But only if the user has not turned off tables or fixed-width regions + (org-set-local + 'auto-fill-inhibit-regexp + (concat "\\*+ \\|#\\+" + "\\|[ \t]*" org-keyword-time-regexp + (if (or org-enable-table-editor org-enable-fixed-width-editor) + (concat + "\\|[ \t]*[" + (if org-enable-table-editor "|" "") + (if org-enable-fixed-width-editor ":" "") + "]")))) + ;; We use our own fill-paragraph function, to make sure that tables + ;; and fixed-width regions are not wrapped. That function will pass + ;; through to `fill-paragraph' when appropriate. + (org-set-local 'fill-paragraph-function 'org-fill-paragraph) + ; Adaptive filling: To get full control, first make sure that + ;; `adaptive-fill-regexp' never matches. Then install our own matcher. + (org-set-local 'adaptive-fill-regexp "\000") + (org-set-local 'adaptive-fill-function + 'org-adaptive-fill-function) + (org-set-local + 'align-mode-rules-list + '((org-in-buffer-settings + (regexp . "^#\\+[A-Z_]+:\\(\\s-*\\)\\S-+") + (modes . '(org-mode)))))) + +(defun org-fill-paragraph (&optional justify) + "Re-align a table, pass through to fill-paragraph if no table." + (let ((table-p (org-at-table-p)) + (table.el-p (org-at-table.el-p))) + (cond ((and (equal (char-after (point-at-bol)) ?*) + (save-excursion (goto-char (point-at-bol)) + (looking-at outline-regexp))) + t) ; skip headlines + (table.el-p t) ; skip table.el tables + (table-p (org-table-align) t) ; align org-mode tables + (t nil)))) ; call paragraph-fill + +;; For reference, this is the default value of adaptive-fill-regexp +;; "[ \t]*\\([-|#;>*]+[ \t]*\\|(?[0-9]+[.)][ \t]*\\)*" + +(defun org-adaptive-fill-function () + "Return a fill prefix for org-mode files. +In particular, this makes sure hanging paragraphs for hand-formatted lists +work correctly." + (cond ((looking-at "#[ \t]+") + (match-string 0)) + ((looking-at "[ \t]*\\([-*+] \\|[0-9]+[.)] \\)?") + (save-excursion + (goto-char (match-end 0)) + (make-string (current-column) ?\ ))) + (t nil))) + ;;;; Functions extending outline functionality -;; C-a should go to the beginning of a *visible* line, also in the -;; new outline.el. I guess this should be patched into Emacs? -(defun org-beginning-of-line () + +(defun org-beginning-of-line (&optional arg) "Go to the beginning of the current line. If that is invisible, continue -to a visible line beginning. This makes the function of C-a more intuitive." - (interactive) - (beginning-of-line 1) - (if (bobp) - nil - (backward-char 1) - (if (org-invisible-p) - (while (and (not (bobp)) (org-invisible-p)) - (backward-char 1) - (beginning-of-line 1)) - (forward-char 1)))) +to a visible line beginning. This makes the function of C-a more intuitive. +If this is a headline, and `org-special-ctrl-a/e' is set, ignore tags on the +first attempt, and only move to after the tags when the cursor is already +beyond the end of the headline." + (interactive "P") + (let ((pos (point))) + (beginning-of-line 1) + (if (bobp) + nil + (backward-char 1) + (if (org-invisible-p) + (while (and (not (bobp)) (org-invisible-p)) + (backward-char 1) + (beginning-of-line 1)) + (forward-char 1))) + (when org-special-ctrl-a/e + (cond + ((and (looking-at org-todo-line-regexp) + (= (char-after (match-end 1)) ?\ )) + (goto-char + (if (eq org-special-ctrl-a/e t) + (cond ((> pos (match-beginning 3)) (match-beginning 3)) + ((= pos (point)) (match-beginning 3)) + (t (point))) + (cond ((> pos (point)) (point)) + ((not (eq last-command this-command)) (point)) + (t (match-beginning 3)))))) + ((org-at-item-p) + (goto-char + (if (eq org-special-ctrl-a/e t) + (cond ((> pos (match-end 4)) (match-end 4)) + ((= pos (point)) (match-end 4)) + (t (point))) + (cond ((> pos (point)) (point)) + ((not (eq last-command this-command)) (point)) + (t (match-end 4)))))))))) + +(defun org-end-of-line (&optional arg) + "Go to the end of the line. +If this is a headline, and `org-special-ctrl-a/e' is set, ignore tags on the +first attempt, and only move to after the tags when the cursor is already +beyond the end of the headline." + (interactive "P") + (if (or (not org-special-ctrl-a/e) + (not (org-on-heading-p))) + (end-of-line arg) + (let ((pos (point))) + (beginning-of-line 1) + (if (looking-at (org-re ".*?\\([ \t]*\\)\\(:[[:alnum:]_@:]+:\\)[ \t]*$")) + (if (eq org-special-ctrl-a/e t) + (if (or (< pos (match-beginning 1)) + (= pos (match-end 0))) + (goto-char (match-beginning 1)) + (goto-char (match-end 0))) + (if (or (< pos (match-end 0)) (not (eq this-command last-command))) + (goto-char (match-end 0)) + (goto-char (match-beginning 1)))) + (end-of-line arg))))) (define-key org-mode-map "\C-a" 'org-beginning-of-line) +(define-key org-mode-map "\C-e" 'org-end-of-line) + +(defun org-kill-line (&optional arg) + "Kill line, to tags or end of line." + (interactive "P") + (cond + ((or (not org-special-ctrl-k) + (bolp) + (not (org-on-heading-p))) + (call-interactively 'kill-line)) + ((looking-at (org-re ".*?\\S-\\([ \t]+\\(:[[:alnum:]_@:]+:\\)\\)[ \t]*$")) + (kill-region (point) (match-beginning 1)) + (org-set-tags nil t)) + (t (kill-region (point) (point-at-eol))))) + +(define-key org-mode-map "\C-k" 'org-kill-line) (defun org-invisible-p () "Check if point is at a character currently not visible." @@ -19689,6 +28565,9 @@ to a visible line beginning. This makes the function of C-a more intuitive." (defalias 'org-back-to-heading 'outline-back-to-heading) (defalias 'org-on-heading-p 'outline-on-heading-p) +(defalias 'org-at-heading-p 'outline-on-heading-p) +(defun org-at-heading-or-item-p () + (or (org-on-heading-p) (org-at-item-p))) (defun org-on-target-p () (or (org-in-regexp org-radio-target-regexp) @@ -19702,6 +28581,35 @@ With argument, move up ARG levels." (outline-up-heading-all arg) ; emacs 21 version of outline.el (outline-up-heading arg t))) ; emacs 22 version of outline.el +(defun org-up-heading-safe () + "Move to the heading line of which the present line is a subheading. +This version will not throw an error. It will return the level of the +headline found, or nil if no higher level is found." + (let ((pos (point)) start-level level + (re (concat "^" outline-regexp))) + (catch 'exit + (outline-back-to-heading t) + (setq start-level (funcall outline-level)) + (if (equal start-level 1) (throw 'exit nil)) + (while (re-search-backward re nil t) + (setq level (funcall outline-level)) + (if (< level start-level) (throw 'exit level))) + nil))) + +(defun org-first-sibling-p () + "Is this heading the first child of its parents?" + (interactive) + (let ((re (concat "^" outline-regexp)) + level l) + (unless (org-at-heading-p t) + (error "Not at a heading")) + (setq level (funcall outline-level)) + (save-excursion + (if (not (re-search-backward re nil t)) + t + (setq l (funcall outline-level)) + (< l level))))) + (defun org-goto-sibling (&optional previous) "Goto the next sibling, even if it is invisible. When PREVIOUS is set, go to the previous sibling instead. Returns t @@ -19711,16 +28619,16 @@ move point." (pos (point)) (re (concat "^" outline-regexp)) level l) - (org-back-to-heading t) - (setq level (funcall outline-level)) - (catch 'exit - (or previous (forward-char 1)) - (while (funcall fun re nil t) - (setq l (funcall outline-level)) - (when (< l level) (goto-char pos) (throw 'exit nil)) - (when (= l level) (goto-char (match-beginning 0)) (throw 'exit t))) - (goto-char pos) - nil))) + (when (condition-case nil (org-back-to-heading t) (error nil)) + (setq level (funcall outline-level)) + (catch 'exit + (or previous (forward-char 1)) + (while (funcall fun re nil t) + (setq l (funcall outline-level)) + (when (< l level) (goto-char pos) (throw 'exit nil)) + (when (= l level) (goto-char (match-beginning 0)) (throw 'exit t))) + (goto-char pos) + nil)))) (defun org-show-siblings () "Show all siblings of the current headline." @@ -19747,11 +28655,11 @@ When ENTRY is non-nil, show the entire entry." (save-excursion (and (outline-next-heading) (org-flag-heading nil)))) - (outline-flag-region (max 1 (1- (point))) + (outline-flag-region (max (point-min) (1- (point))) (save-excursion (outline-end-of-heading) (point)) flag)))) -(defun org-end-of-subtree (&optional invisible-OK) +(defun org-end-of-subtree (&optional invisible-OK to-heading) ;; This is an exact copy of the original function, but it uses ;; `org-back-to-heading', to make it work also in invisible ;; trees. And is uses an invisible-OK argument. @@ -19763,13 +28671,14 @@ When ENTRY is non-nil, show the entire entry." (or first (> (funcall outline-level) level))) (setq first nil) (outline-next-heading)) - (if (memq (preceding-char) '(?\n ?\^M)) - (progn - ;; Go to end of line before heading - (forward-char -1) - (if (memq (preceding-char) '(?\n ?\^M)) - ;; leave blank line before heading - (forward-char -1))))) + (unless to-heading + (if (memq (preceding-char) '(?\n ?\^M)) + (progn + ;; Go to end of line before heading + (forward-char -1) + (if (memq (preceding-char) '(?\n ?\^M)) + ;; leave blank line before heading + (forward-char -1)))))) (point)) (defun org-show-subtree () @@ -19785,13 +28694,17 @@ When ENTRY is non-nil, show the entire entry." Show the heading too, if it is currently invisible." (interactive) (save-excursion - (org-back-to-heading t) - (outline-flag-region - (max 1 (1- (point))) - (save-excursion - (re-search-forward (concat "[\r\n]\\(" outline-regexp "\\)") nil 'move) - (or (match-beginning 1) (point-max))) - nil))) + (condition-case nil + (progn + (org-back-to-heading t) + (outline-flag-region + (max (point-min) (1- (point))) + (save-excursion + (re-search-forward + (concat "[\r\n]\\(" outline-regexp "\\)") nil 'move) + (or (match-beginning 1) (point-max))) + nil)) + (error nil)))) (defun org-make-options-regexp (kwds) "Make a regular expression for keyword lines." @@ -19824,7 +28737,110 @@ Show the heading too, if it is currently invisible." (remove-hook 'post-command-hook 'org-isearch-post-command 'local) (org-show-context 'isearch)) -;;;; Repair problems with some other packages + +;;;; Integration with and fixes for other packages + +;;; Imenu support + +(defvar org-imenu-markers nil + "All markers currently used by Imenu.") +(make-variable-buffer-local 'org-imenu-markers) + +(defun org-imenu-new-marker (&optional pos) + "Return a new marker for use by Imenu, and remember the marker." + (let ((m (make-marker))) + (move-marker m (or pos (point))) + (push m org-imenu-markers) + m)) + +(defun org-imenu-get-tree () + "Produce the index for Imenu." + (mapc (lambda (x) (move-marker x nil)) org-imenu-markers) + (setq org-imenu-markers nil) + (let* ((n org-imenu-depth) + (re (concat "^" outline-regexp)) + (subs (make-vector (1+ n) nil)) + (last-level 0) + m tree level head) + (save-excursion + (save-restriction + (widen) + (goto-char (point-max)) + (while (re-search-backward re nil t) + (setq level (org-reduced-level (funcall outline-level))) + (when (<= level n) + (looking-at org-complex-heading-regexp) + (setq head (org-match-string-no-properties 4) + m (org-imenu-new-marker)) + (org-add-props head nil 'org-imenu-marker m 'org-imenu t) + (if (>= level last-level) + (push (cons head m) (aref subs level)) + (push (cons head (aref subs (1+ level))) (aref subs level)) + (loop for i from (1+ level) to n do (aset subs i nil))) + (setq last-level level))))) + (aref subs 1))) + +(eval-after-load "imenu" + '(progn + (add-hook 'imenu-after-jump-hook + (lambda () (org-show-context 'org-goto))))) + +;; Speedbar support + +(defun org-speedbar-set-agenda-restriction () + "Restrict future agenda commands to the location at point in speedbar. +To get rid of the restriction, use \\[org-agenda-remove-restriction-lock]." + (interactive) + (let (p m tp np dir txt w) + (cond + ((setq p (text-property-any (point-at-bol) (point-at-eol) + 'org-imenu t)) + (setq m (get-text-property p 'org-imenu-marker)) + (save-excursion + (save-restriction + (set-buffer (marker-buffer m)) + (goto-char m) + (org-agenda-set-restriction-lock 'subtree)))) + ((setq p (text-property-any (point-at-bol) (point-at-eol) + 'speedbar-function 'speedbar-find-file)) + (setq tp (previous-single-property-change + (1+ p) 'speedbar-function) + np (next-single-property-change + tp 'speedbar-function) + dir (speedbar-line-directory) + txt (buffer-substring-no-properties (or tp (point-min)) + (or np (point-max)))) + (save-excursion + (save-restriction + (set-buffer (find-file-noselect + (let ((default-directory dir)) + (expand-file-name txt)))) + (unless (org-mode-p) + (error "Cannot restrict to non-Org-mode file")) + (org-agenda-set-restriction-lock 'file)))) + (t (error "Don't know how to restrict Org-mode's agenda"))) + (org-move-overlay org-speedbar-restriction-lock-overlay + (point-at-bol) (point-at-eol)) + (setq current-prefix-arg nil) + (org-agenda-maybe-redo))) + +(eval-after-load "speedbar" + '(progn + (speedbar-add-supported-extension ".org") + (define-key speedbar-file-key-map "<" 'org-speedbar-set-agenda-restriction) + (define-key speedbar-file-key-map "\C-c\C-x<" 'org-speedbar-set-agenda-restriction) + (define-key speedbar-file-key-map ">" 'org-agenda-remove-restriction-lock) + (define-key speedbar-file-key-map "\C-c\C-x>" 'org-agenda-remove-restriction-lock) + (add-hook 'speedbar-visiting-tag-hook + (lambda () (org-show-context 'org-goto))))) + + +;;; Fixes and Hacks + +;; Make flyspell not check words in links, to not mess up our keymap +(defun org-mode-flyspell-verify () + "Don't let flyspell put overlays at active buttons." + (not (get-text-property (point) 'keymap))) ;; Make `bookmark-jump' show the jump location if it was hidden. (eval-after-load "bookmark" @@ -19850,6 +28866,27 @@ Show the heading too, if it is currently invisible." ;;;; Experimental code +(defun org-closed-in-range () + "Sparse tree of items closed in a certain time range. +Still experimental, may disappear in the future." + (interactive) + ;; Get the time interval from the user. + (let* ((time1 (time-to-seconds + (org-read-date nil 'to-time nil "Starting date: "))) + (time2 (time-to-seconds + (org-read-date nil 'to-time nil "End date:"))) + ;; callback function + (callback (lambda () + (let ((time + (time-to-seconds + (apply 'encode-time + (org-parse-time-string + (match-string 1)))))) + ;; check if time in interval + (and (>= time time1) (<= time time2)))))) + ;; make tree, check each match with the callback + (org-occur "CLOSED: +\\[\\(.*?\\)\\]" nil callback))) + ;;;; Finish up diff --git a/man/ChangeLog b/man/ChangeLog index 59e294d9d8d..d2e8838af61 100644 --- a/man/ChangeLog +++ b/man/ChangeLog @@ -1,3 +1,8 @@ +2008-04-08 Carsten Dominik + + * org.texi: Large scale rewrite and changes, moving from version 4.67 + to version 5.23. + 2008-03-28 Jason Rumney * display.texi (Display Custom): Mention overlay-margin in text. From cfab57d770f10355a4a164042ca2321a3c72e563 Mon Sep 17 00:00:00 2001 From: Carsten Dominik Date: Tue, 8 Apr 2008 07:47:49 +0000 Subject: [PATCH 24/56] * org.texi: Large scale rewrite and changes, moving from version 4.67 to version 5.23. --- man/org.texi | 5244 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 3738 insertions(+), 1506 deletions(-) diff --git a/man/org.texi b/man/org.texi index 9429eb5c78c..7c32c2e0e3b 100644 --- a/man/org.texi +++ b/man/org.texi @@ -3,8 +3,8 @@ @setfilename ../info/org @settitle Org Mode Manual -@set VERSION 4.67 -@set DATE February 2007 +@set VERSION 5.23 +@set DATE March 2008 @dircategory Emacs @direntry @@ -12,11 +12,11 @@ @end direntry @c Version and Contact Info -@set MAINTAINERSITE @uref{http://orgmode.org/,maintainers webpage} +@set MAINTAINERSITE @uref{http://orgmode.org,maintainers webpage} @set AUTHOR Carsten Dominik @set MAINTAINER Carsten Dominik -@set MAINTAINEREMAIL @email{dominik at science dot uva dot nl} -@set MAINTAINERCONTACT @uref{mailto:dominik at science dot uva dot nl,contact the maintainer} +@set MAINTAINEREMAIL @email{carsten at orgmode dot org} +@set MAINTAINERCONTACT @uref{mailto:carsten at orgmode dot org,contact the maintainer} @c %**end of header @finalout @@ -80,17 +80,18 @@ Software Foundation raise funds for GNU development.'' * Tables:: Pure magic for quick formatting * Hyperlinks:: Notes in context * TODO items:: Every tree branch can be a TODO item -* Timestamps:: Assign date and time to items * Tags:: Tagging headlines and matching sets of tags +* Properties and columns:: Storing information about an entry +* Dates and times:: Making items useful for planning +* Remember:: Quickly adding nodes to the outline tree * Agenda views:: Collecting information into views * Embedded LaTeX:: LaTeX fragments and formulas * Exporting:: Sharing and publishing of notes * Publishing:: Create a web site of linked Org-mode files * Miscellaneous:: All the rest which did not fit elsewhere * Extensions and Hacking:: It is possible to write add-on code -* History and Acknowledgments:: How Org-mode came into being -* GNU Free Documentation License:: The license for this documentation. -* Index:: The fast road to specific information +* History and Acknowledgments:: How Org-mode came into being +* Main Index:: * Key Index:: Key bindings and where they are described @detailmenu @@ -102,6 +103,7 @@ Introduction * Installation:: How to install a downloaded version of Org-mode * Activation:: How to activate Org-mode for certain buffers. * Feedback:: Bug reports, ideas, patches etc. +* Conventions:: Type-setting conventions in the manual Document Structure @@ -113,6 +115,8 @@ Document Structure * Archiving:: Move done task trees to a different place * Sparse trees:: Matches embedded in context * Plain lists:: Additional structure within an entry +* Drawers:: Tucking stuff away +* orgstruct-mode:: Structure editing outside Org-mode Archiving @@ -122,7 +126,8 @@ Archiving Tables * Built-in table editor:: Simple tables -* Narrow columns:: Stop wasting space in tables +* Narrow columns:: Stop wasting space in tables +* Column groups:: Grouping to trigger vertical lines * orgtbl-mode:: The table editor as minor mode * The spreadsheet:: The table editor has spreadsheet capabilities. @@ -143,52 +148,37 @@ Hyperlinks * Internal links:: Links to other places in the current file * External links:: URL-like links to the world * Handling links:: Creating, inserting and following +* Using links outside Org-mode:: Linking from my C source code? * Link abbreviations:: Shortcuts for writing complex links * Search options:: Linking to a specific location * Custom searches:: When the default search is not enough -* Remember:: Org-trees store quick notes Internal links * Radio targets:: Make targets trigger links in plain text. -Remember - -* Setting up remember:: Some code for .emacs to get things going -* Remember templates:: Define the outline of different note types -* Storing notes:: Directly get the note to where it belongs - TODO items * TODO basics:: Marking and displaying TODO entries * TODO extensions:: Workflow and assignments +* Progress logging:: Dates and notes for progress * Priorities:: Some things are more important than others -* Breaking down tasks:: Splitting a task into managable pieces +* Breaking down tasks:: Splitting a task into manageable pieces * Checkboxes:: Tick-off lists Extended use of TODO keywords * Workflow states:: From TODO to DONE in steps -* TODO types:: I do this, Fred the rest -* Per file keywords:: Different files, different requirements - -Timestamps - -* Time stamps:: Assigning a time to a tree entry -* Creating timestamps:: Commands which insert timestamps -* Custom time format:: If you cannot work with the ISO format -* Repeating items:: Deadlines that come back again and again -* Progress logging:: Documenting when what work was done. - -Creating timestamps - -* The date/time prompt:: How org-mode helps you entering date and time +* TODO types:: I do this, Fred does the rest +* Multiple sets in one file:: Mixing it all, and still finding your way +* Fast access to TODO states:: Single letter selection of a state +* Per-file keywords:: Different files, different requirements +* Faces for TODO keywords:: Highlighting states Progress Logging * Closing items:: When was this entry marked DONE? * Tracking TODO state changes:: When did the status change? -* Clocking work time:: When exactly did you work on this item? Tags @@ -196,6 +186,50 @@ Tags * Setting tags:: How to assign tags to a headline * Tag searches:: Searching for combinations of tags +Properties and Columns + +* Property syntax:: How properties are spelled out +* Special properties:: Access to other Org-mode features +* Property searches:: Matching property values +* Property inheritance:: Passing values down the tree +* Column view:: Tabular viewing and editing +* Property API:: Properties for Lisp programmers + +Column View + +* Defining columns:: The COLUMNS format property +* Using column view:: How to create and use column view +* Capturing Column View:: A dynamic block for column view + +Defining Columns + +* Scope of column definitions:: Where defined, where valid? +* Column attributes:: Appearance and content of a column + +Dates and Times + +* Time stamps:: Assigning a time to a tree entry +* Creating timestamps:: Commands which insert timestamps +* Deadlines and scheduling:: Planning your work +* Clocking work time:: + +Creating timestamps + +* The date/time prompt:: How org-mode helps you entering date and time +* Custom time format:: Making dates look differently + +Deadlines and Scheduling + +* Inserting deadline/schedule:: Planning items +* Repeated tasks:: Items that show up again and again + +Remember + +* Setting up remember:: Some code for .emacs to get things going +* Remember templates:: Define the outline of different note types +* Storing notes:: Directly get the note to where it belongs +* Refiling notes:: Moving a note or task to a project + Agenda Views * Agenda files:: Files being searched for agenda information @@ -209,8 +243,9 @@ The built-in agenda views * Weekly/Daily agenda:: The calendar page with current tasks * Global TODO list:: All unfinished action items -* Matching headline tags:: Structured information with fine-tuned search +* Matching tags and properties:: Structured information with fine-tuned search * Timeline:: Time-sorted view for single file +* Keyword search:: Finding entries by keyword * Stuck projects:: Find projects you need to review Presentation and sorting @@ -224,7 +259,8 @@ Custom agenda views * Storing searches:: Type once, use often * Block agenda:: All the stuff you need in a single buffer * Setting Options:: Changing the rules -* Batch processing:: Agenda views from the command line +* Exporting Agenda Views:: Writing agendas to files. +* Extracting Agenda Information for other programs:: Embedded LaTeX @@ -238,21 +274,31 @@ Exporting * ASCII export:: Exporting to plain ASCII * HTML export:: Exporting to HTML +* LaTeX export:: Exporting to LaTeX * XOXO export:: Exporting to XOXO * iCalendar export:: Exporting in iCalendar format * Text interpretation:: How the exporter looks at the file HTML export -* Export commands:: How to invode HTML export +* HTML Export commands:: How to invoke LaTeX export * Quoting HTML tags:: Using direct HTML in Org-mode -* Links:: How hyperlinks get transferred to HTML -* Images:: To inline or not to inline? -* CSS support:: Style specifications +* Links:: Transformation of links for HTML +* Images:: How to include images +* CSS support:: Changing the appearence of the output + +LaTeX export + +* LaTeX export commands:: How to invoke LaTeX export +* Quoting LaTeX code:: Incorporating literal LaTeX code +* Sectioning structure:: Text interpretation by the exporter * Comment lines:: Some lines will not be exported +* Initial text:: Text before the first headline +* Footnotes:: Numbers like [1] +* Quoted examples:: Inserting quoted chnuks of text * Enhancing text:: Subscripts, symbols and more * Export options:: How to influence the export settings @@ -296,15 +342,18 @@ Interaction with other packages Extensions, Hooks and Hacking * Extensions:: Existing 3rd-part extensions +* Adding hyperlink types:: New custom link types * Tables in arbitrary syntax:: Orgtbl for LaTeX and other programs * Dynamic blocks:: Automatically filled blocks * Special agenda views:: Customized views +* Using the property API:: Writing programs that use entry properties -Tables in arbitrary syntax +Tables and Lists in arbitrary syntax * Radio tables:: Sending and receiving * A LaTeX example:: Step by step, almost a tutorial * Translator functions:: Copy and modify +* Radio lists:: Doing the same for lists. @end detailmenu @end menu @@ -318,13 +367,14 @@ Tables in arbitrary syntax * Installation:: How to install a downloaded version of Org-mode * Activation:: How to activate Org-mode for certain buffers. * Feedback:: Bug reports, ideas, patches etc. +* Conventions:: Type-setting conventions in the manual @end menu @node Summary, Installation, Introduction, Introduction @section Summary @cindex summary -Org-mode is a mode for keeping notes, maintaining ToDo lists, and doing +Org-mode is a mode for keeping notes, maintaining TODO lists, and doing project planning with a fast and effective plain-text system. Org-mode develops organizational tasks around NOTES files that contain @@ -332,13 +382,13 @@ lists or information about projects as plain text. Org-mode is implemented on top of outline-mode, which makes it possible to keep the content of large files well structured. Visibility cycling and structure editing help to work with the tree. Tables are easily created -with a built-in table editor. Org-mode supports ToDo items, deadlines, +with a built-in table editor. Org-mode supports TODO items, deadlines, time stamps, and scheduling. It dynamically compiles entries into an agenda that utilizes and smoothly integrates much of the Emacs calendar and diary. Plain text URL-like links connect to websites, emails, Usenet messages, BBDB entries, and any files related to the projects. For printing and sharing of notes, an Org-mode file can be exported as a -structured ASCII file, as HTML, or (todo and agenda items only) as an +structured ASCII file, as HTML, or (TODO and agenda items only) as an iCalendar file. It can also serve as a publishing tool for a set of linked webpages. @@ -354,7 +404,7 @@ tags etc are created dynamically when you need them. Org-mode keeps simple things simple. When first fired up, it should feel like a straightforward, easy to use outliner. Complexity is not imposed, but a large amount of functionality is available when you need -it. Org-mode can be used on different levels and in different ways, for +it. Org-mode is a toolbox and can be used in different ways, for example as: @example @@ -364,20 +414,23 @@ example as: @r{@bullet{} TODO list editor} @r{@bullet{} full agenda and planner with deadlines and work scheduling} @r{@bullet{} environment to implement David Allen's GTD system} -@r{@bullet{} simple hypertext system, with HTML export} +@r{@bullet{} a basic database application} +@r{@bullet{} simple hypertext system, with HTML and LaTeX export} @r{@bullet{} publishing tool to create a set of interlinked webpages} @end example Org-mode's automatic, context sensitive table editor with spreadsheet capabilities can be integrated into any major mode by activating the minor Orgtbl-mode. Using a translation step, it can be used to maintain -tables in arbitray file types, for example in LaTeX. +tables in arbitrary file types, for example in La@TeX{}. The structure +editing and list creation capabilities can be used outside Org-mode with +the minor Orgstruct-mode. @cindex FAQ There is a website for Org-mode which provides links to the newest version of Org-mode, as well as additional information, frequently asked questions (FAQ), links to tutorials etc. This page is located at -@uref{http://orgmode.org/}. +@uref{http://orgmode.org}. @page @@ -443,9 +496,10 @@ make install-info @iftex @b{Important:} @i{If you use copy-and-paste to copy lisp code from the -PDF documentation to your .emacs file, the single quote character comes -out incorrectly and the code will not work. You need to fix the single -quotes by hand, or copy from Info documentation.} +PDF documentation as viewed by Acrobat reader to your .emacs file, the +single quote character comes out incorrectly and the code will not work. +You need to fix the single quotes by hand, or copy from Info +documentation.} @end iftex Add the following lines to your @file{.emacs} file. The last two lines @@ -454,9 +508,9 @@ define @emph{global} keys for the commands @command{org-store-link} and @lisp ;; The following lines are always needed. Choose your own keys. -(add-to-list 'auto-mode-alist '("\\.org$" . org-mode)) -(define-key global-map "\C-cl" 'org-store-link) -(define-key global-map "\C-ca" 'org-agenda) +(add-to-list 'auto-mode-alist '("\\.org\\'" . org-mode)) +(global-set-key "\C-cl" 'org-store-link) +(global-set-key "\C-ca" 'org-agenda) @end lisp Furthermore, you must activate @code{font-lock-mode} in org-mode @@ -481,7 +535,7 @@ MY PROJECTS -*- mode: org; -*- the file's name is. See also the variable @code{org-insert-mode-line-in-empty-file}. -@node Feedback, , Activation, Introduction +@node Feedback, Conventions, Activation, Introduction @section Feedback @cindex feedback @cindex bug reports @@ -538,6 +592,27 @@ screen. Save this buffer to a file (for example using @kbd{C-x C-w}) and attach it to your bug report. @end enumerate +@node Conventions, , Feedback, Introduction +@section Typesetting conventions used in this manual + +Org-mode uses three types of keywords: TODO keywords, tags, and property +names. In this manual we use the following conventions: + +@table @code +@item TODO +@itemx WAITING +TODO keywords are written with all capitals, even if they are +user-defined. +@item boss +@itemx ARCHIVE +User-defined tags are written in lowercase; built-in tags with special +meaning are written with all capitals. +@item Release +@itemx PRIORITY +User-defined properties are capitalized; built-in properties with +special meaning are written with all capitals. +@end table + @node Document structure, Tables, Introduction, Top @chapter Document Structure @cindex document structure @@ -555,6 +630,8 @@ edit the structure of the document. * Archiving:: Move done task trees to a different place * Sparse trees:: Matches embedded in context * Plain lists:: Additional structure within an entry +* Drawers:: Tucking stuff away +* orgstruct-mode:: Structure editing outside Org-mode @end menu @node Outlines, Headlines, Document structure, Document structure @@ -562,15 +639,14 @@ edit the structure of the document. @cindex outlines @cindex outline-mode -Org-mode is implemented on top of outline-mode. Outlines allow to -organize a document in a hierarchical structure, which (at least for -me) is the best representation of notes and thoughts. Overview over -this structure is achieved by folding (hiding) large parts of the +Org-mode is implemented on top of outline-mode. Outlines allow a +document to be organized in a hierarchical structure, which (at least +for me) is the best representation of notes and thoughts. An overview +of this structure is achieved by folding (hiding) large parts of the document to show only the general document structure and the parts currently being worked on. Org-mode greatly simplifies the use of -outlines by compressing the entire show/hide functionality into a -single command @command{org-cycle}, which is bound to the @key{TAB} -key. +outlines by compressing the entire show/hide functionality into a single +command @command{org-cycle}, which is bound to the @key{TAB} key. @node Headlines, Visibility cycling, Outlines, Document structure @section Headlines @@ -578,8 +654,9 @@ key. @cindex outline tree Headlines define the structure of an outline tree. The headlines in -Org-mode start with one or more stars, on the left margin. For -example: +Org-mode start with one or more stars, on the left margin@footnote{See +the variable @code{org-special-ctrl-a/e} to configure special behavior +of @kbd{C-a} and @kbd{C-e} in headlines.}. For example: @example * Top level headline @@ -588,6 +665,7 @@ example: some text *** 3rd level more text + * Another top level headline @end example @@ -595,6 +673,12 @@ example: outline that has whitespace followed by a single star as headline starters. @ref{Clean view} describes a setup to realize this. +An empty line after the end of a subtree is considered part of it and +will be hidden when the subtree is folded. However, if you leave at +least two empty lines, one empty line will remain visible after folding +the subtree, in order to structure the collapsed view. See the +variable @code{org-cycle-separator-lines} to modify this behavior. + @node Visibility cycling, Motion, Headlines, Document structure @section Visibility cycling @cindex cycling, visibility @@ -615,7 +699,7 @@ Org-mode uses just two commands, bound to @key{TAB} and @table @kbd @kindex @key{TAB} @item @key{TAB} -@emph{Subtree cycling}: Rotate current subtree between the states +@emph{Subtree cycling}: Rotate current subtree among the states @example ,-> FOLDED -> CHILDREN -> SUBTREE --. @@ -637,7 +721,7 @@ argument (@kbd{C-u @key{TAB}}), global cycling is invoked. @kindex S-@key{TAB} @item S-@key{TAB} @itemx C-u @key{TAB} -@emph{Global cycling}: Rotate the entire buffer between the states +@emph{Global cycling}: Rotate the entire buffer among the states @example ,-> OVERVIEW -> CONTENTS -> SHOW ALL --. @@ -656,19 +740,27 @@ Show all. @item C-c C-r Reveal context around point, showing the current entry, the following heading and the hierarchy above. Useful for working near a location -exposed by a sparse tree command (@pxref{Sparse trees}) or an agenda -command (@pxref{Agenda commands}). With prefix arg show, on each +that has been exposed by a sparse tree command (@pxref{Sparse trees}) or +an agenda command (@pxref{Agenda commands}). With prefix arg show, on +each + level, all sibling headings. @kindex C-c C-x b @item C-c C-x b Show the current subtree in an indirect buffer@footnote{The indirect -buffer (@pxref{Indirect Buffers,Indirect Buffers,Indirect -Buffers,emacs,GNU Emacs Manual}) will contain the entire buffer, but -will be narrowed to the current tree. Editing the indirect buffer will -also change the original buffer, but without affecting visibility in -that buffer.}. With numerical prefix ARG, go up to this level and then -take that tree. If ARG is negative, go up that many levels. With -@kbd{C-u} prefix, do not remove the previously used indirect buffer. +buffer +@ifinfo +(@pxref{Indirect Buffers,,,emacs,GNU Emacs Manual}) +@end ifinfo +@ifnotinfo +(see the Emacs manual for more information about indirect buffers) +@end ifnotinfo +will contain the entire buffer, but will be narrowed to the current +tree. Editing the indirect buffer will also change the original buffer, +but without affecting visibility in that buffer.}. With numerical +prefix ARG, go up to this level and then take that tree. If ARG is +negative, go up that many levels. With @kbd{C-u} prefix, do not remove +the previously used indirect buffer. @end table When Emacs first visits an Org-mode file, the global state is set to @@ -710,10 +802,16 @@ Backward to higher level heading. @item C-c C-j Jump to a different place without changing the current outline visibility. Shows the document structure in a temporary buffer, where -you can use visibility cycling (@key{TAB}) to find your destination. -After pressing @key{RET}, the cursor moves to the selected location in -the original buffer, and the headings hierarchy above it is made -visible. +you can use the following keys to find your destination: +@example +@key{TAB} @r{Cycle visibility.} +@key{down} / @key{up} @r{Next/previous visible headline.} +n / p @r{Next/previous visible headline.} +f / b @r{Next/previous headline same level.} +u @r{One level up.} +0-9 @r{Digit argument.} +@key{RET} @r{Select this location.} +@end example @end table @node Structure editing, Archiving, Motion, Document structure @@ -736,12 +834,18 @@ plain list item, a new item is created (@pxref{Plain lists}). To force creation of a new headline, use a prefix arg, or first press @key{RET} to get to the beginning of the next line. When this command is used in the middle of a line, the line is split and the rest of the line becomes -the new headline. If the command is used at the beginning of a -headline, the new headline is created before the current line. If at -the beginning of any other line, the content of that line is made the -new heading. If the command is used at the end of a folded subtree -(i.e. behind the ellipses at the end of a headline), then a headline -like the current one will be inserted after the end of the subtree. +the new headline@footnote{If you do not want the line to be split, +customize the variable @code{org-M-RET-may-split-line}.}. If the +command is used at the beginning of a headline, the new headline is +created before the current line. If at the beginning of any other line, +the content of that line is made the new heading. If the command is +used at the end of a folded subtree (i.e. behind the ellipses at the end +of a headline), then a headline like the current one will be inserted +after the end of the subtree. +@kindex C-@key{RET} +@item C-@key{RET} +Insert a new heading after the current subtree, same level as the +current headline. This command works from anywhere in the entry. @kindex M-S-@key{RET} @item M-S-@key{RET} Insert new TODO entry with same level as current heading. @@ -769,24 +873,36 @@ Move subtree down (swap with next subtree of same level). @item C-c C-x C-w @itemx C-c C-x C-k Kill subtree, i.e. remove it from buffer but save in kill ring. +With prefix arg, kill N sequential subtrees. @kindex C-c C-x M-w @item C-c C-x M-w -Copy subtree to kill ring. +Copy subtree to kill ring. With prefix arg, copy N sequential subtrees. @kindex C-c C-x C-y @item C-c C-x C-y Yank subtree from kill ring. This does modify the level of the subtree to make sure the tree fits in nicely at the yank position. The yank level can also be specified with a prefix arg, or by yanking after a headline marker like @samp{****}. +@kindex C-c C-w +@item C-c C-w +Refile entry to a different location. @xref{Refiling notes}. @kindex C-c ^ @item C-c ^ Sort same-level entries. When there is an active region, all entries in the region will be sorted. Otherwise the children of the current headline are sorted. The command prompts for the sorting method, which can be alphabetically, numerically, by time (using the first time stamp -in each entry), and each of these in reverse order. With a @kbd{C-u} -prefix, sorting will be case-sensitive. With two @kbd{C-u C-u} -prefixes, duplicate entries will also be removed. +in each entry), by priority, and each of these in reverse order. You +can also supply your own function to extract the sorting key. With a +@kbd{C-u} prefix, sorting will be case-sensitive. With two @kbd{C-u +C-u} prefixes, duplicate entries will also be removed. +@kindex C-c * +@item C-c * +Turn a normal line or plain list item into a headline (so that it +becomes a subheading at its location). Also turn a headline into a +normal line by removing the stars. If there is an active region, turn +all lines in the region into headlines. Or, if the first line is a +headline, remove the stars from all headlines in the region. @end table @cindex region, active @@ -874,7 +990,9 @@ file, the archive file. @kindex C-c C-x C-s @item C-c C-x C-s Archive the subtree starting at the cursor position to the location -given by @code{org-archive-location}. +given by @code{org-archive-location}. Context information that could be +lost like the file name, the category, inherited tags, and the todo +state will be store as properties in the entry. @kindex C-u C-c C-x C-s @item C-u C-c C-x C-s Check if any direct children of the current headline could be moved to @@ -890,16 +1008,28 @@ current file, with the name derived by appending @file{_archive} to the current file name. For information and examples on how to change this, see the documentation string of the variable @code{org-archive-location}. There is also an in-buffer option for -setting this variable, for example +setting this variable, for example@footnote{For backward compatibility, +the following also works: If there are several such lines in a file, +each specifies the archive location for the text below it. The first +such line also applies to any text before its definition. However, +using this method is @emph{strongly} deprecated as it is incompatible +with the outline structure of the document. The correct method for +setting multiple archive locations in a buffer is using a property.}: @example #+ARCHIVE: %s_done:: @end example @noindent -You may have several such lines in the buffer, they will then be valid -for the entries following the line (the first will also apply to any -text before it). +If you would like to have a special ARCHIVE location for a single entry +or a (sub)tree, give the entry an @code{:ARCHIVE:} property with the +location as the value (@pxref{Properties and columns}). + +When a subtree is moved, it receives a number of special properties that +record context information like the file from where the entry came, it's +outline path the archiving time etc. Configure the variable +@code{org-archive-save-context-info} to adjust the amount of information +added. @node Sparse trees, Plain lists, Archiving, Document structure @section Sparse trees @@ -909,31 +1039,34 @@ text before it). @cindex occur, command An important feature of Org-mode is the ability to construct -@emph{sparse trees} for selected information in an outline tree. A -sparse tree means that the entire document is folded as much as -possible, but the selected information is made visible along with the -headline structure above it@footnote{See also the variables -@code{org-show-hierarchy-above}, @code{org-show-following-heading}, and -@code{org-show-siblings} for detailed control on how much context is -shown around each match.}. Just try it out and you will see immediately -how it works. +@emph{sparse trees} for selected information in an outline tree, so that +the entire document is folded as much as possible, but the selected +information is made visible along with the headline structure above +it@footnote{See also the variables @code{org-show-hierarchy-above}, +@code{org-show-following-heading}, and @code{org-show-siblings} for +detailed control on how much context is shown around each match.}. Just +try it out and you will see immediately how it works. -Org-mode contains several commands creating such trees. The most -basic one is @command{org-occur}: +Org-mode contains several commands creating such trees, all these +commands can be accessed through a dispatcher: @table @kbd @kindex C-c / @item C-c / +This prompts for an extra key to select a sparse-tree creating command. +@kindex C-c / r +@item C-c / r Occur. Prompts for a regexp and shows a sparse tree with all matches. If the match is in a headline, the headline is made visible. If the match is in the body of an entry, headline and body are made visible. In order to provide minimal context, also the full hierarchy of headlines above the match is shown, as well as the headline following the match. Each match is also highlighted; the highlights disappear -when the buffer is changes an editing command, or by pressing @kbd{C-c -C-c}. When called with a @kbd{C-u} prefix argument, previous highlights -are kept, so several calls to this command can be stacked. +when the buffer is changed by an editing command, or by pressing +@kbd{C-c C-c}. When called with a @kbd{C-u} prefix argument, previous +highlights are kept, so several calls to this command can be stacked. @end table + @noindent For frequently used sparse trees of specific search strings, you can use the variable @code{org-agenda-custom-commands} to define fast @@ -949,8 +1082,8 @@ For example: @noindent will define the key @kbd{C-c a f} as a shortcut for creating a sparse tree matching the string @samp{FIXME}. -Other commands use sparse trees as well. For example @kbd{C-c -C-v} creates a sparse TODO tree (@pxref{TODO basics}). +The other sparse tree commands select headings based on TODO keywords, +tags, or properties and will be discussed later in this manual. @kindex C-c C-e v @cindex printing sparse trees @@ -962,7 +1095,7 @@ XEmacs uses selective display for outlining, not text properties.}. Or you can use the command @kbd{C-c C-e v} to export only the visible part of the document and print the resulting file. -@node Plain lists, , Sparse trees, Document structure +@node Plain lists, Drawers, Sparse trees, Document structure @section Plain lists @cindex plain lists @cindex lists, plain @@ -972,7 +1105,7 @@ part of the document and print the resulting file. Within an entry of the outline tree, hand-formatted lists can provide additional structure. They also provide a way to create lists of checkboxes (@pxref{Checkboxes}). Org-mode supports editing such lists, -and the HTML exporter (@pxref{Exporting}) does parse and format them. +and the HTML exporter (@pxref{Exporting}) parses and formats them. Org-mode knows ordered and unordered lists. Unordered list items start with @samp{-}, @samp{+}, or @samp{*}@footnote{When using @samp{*} as a @@ -980,14 +1113,18 @@ bullet, lines must be indented or they will be seen as top-level headlines. Also, when you are hiding leading stars to get a clean outline view, plain list items starting with a star are visually indistinguishable from true headlines. In short: even though @samp{*} -is supported, it may be better not to use it for plain list items} as -bullets. Ordered list items start with @samp{1.} or @samp{1)}. Items +is supported, it may be better to not use it for plain list items.} as +bullets. Ordered list items start with a numeral followed by either a +period or a right parenthesis, such as @samp{1.} or @samp{1)}. Items belonging to the same list must have the same indentation on the first line. In particular, if an ordered list reaches number @samp{10.}, then the 2--digit numbers must be written left-aligned with the other numbers in the list. Indentation also determines the end of a list item. It ends before the next line that is indented like the bullet/number, or -less. For example: +less. Empty lines are part of the previous item, so you can have +several paragraphs in one item. If you would like an empty line to +terminate all currently open plain lists, configure the variable +@code{org-empty-line-terminates-plain-lists}. Here is an example: @example @group @@ -1008,10 +1145,7 @@ Org-mode supports these lists by tuning filling and wrapping commands to deal with them correctly@footnote{Org-mode only changes the filling settings for Emacs. For XEmacs, you should use Kyle E. Jones' @file{filladapt.el}. To turn this on, put into @file{.emacs}: -@example -(require 'filladapt) -@end example -}. +@code{(require 'filladapt)}}. The following commands act on items when the cursor is in the first line of an item (the line with the bullet or number). @@ -1024,16 +1158,20 @@ Items can be folded just like headline levels if you set the variable given by the indentation of the bullet/number. Items are always subordinate to real headlines, however; the hierarchies remain completely separated. + +If @code{org-cycle-include-plain-lists} has not been set, @key{TAB} +fixes the indentation of the curent line in a heuristic way. @kindex M-@key{RET} @item M-@key{RET} Insert new item at current level. With prefix arg, force a new heading (@pxref{Structure editing}). If this command is used in the middle of a line, the line is @emph{split} and the rest of the line becomes the new -item. If this command is executed in the @emph{whitespace before a bullet or -number}, the new item is created @emph{before} the current item. If the -command is executed in the white space before the text that is part of -an item but does not contain the bullet, a bullet is added to the -current line. +item@footnote{If you do not want the line to be split, customize the +variable @code{org-M-RET-may-split-line}.}. If this command is executed +in the @emph{whitespace before a bullet or number}, the new item is +created @emph{before} the current item. If the command is executed in +the white space before the text that is part of an item but does not +contain the bullet, a bullet is added to the current line. @kindex M-S-@key{RET} @item M-S-@key{RET} Insert a new item with a checkbox (@pxref{Checkboxes}). @@ -1062,22 +1200,90 @@ the command chain with a cursor motion or so. @kindex C-c C-c @item C-c C-c If there is a checkbox (@pxref{Checkboxes}) in the item line, toggle the -state of the checkbox. Otherwise, if this is an ordered list, renumber -the ordered list at the cursor. +state of the checkbox. If not, this command makes sure that all the +items on this list level use the same bullet. Furthermore, if this is +an ordered list, make sure the numbering is ok. +@kindex C-c - +@item C-c - +Cycle the entire list level through the different itemize/enumerate +bullets (@samp{-}, @samp{+}, @samp{*}, @samp{1.}, @samp{1)}). +With prefix arg, select the nth bullet from this list. +If there is an active region when calling this, all lines will be +converted to list items. If the first line already was a list item, any +item markers will be removed from the list. Finally, even without an +active region, a normal line will be converted into a list item. @end table +@node Drawers, orgstruct-mode, Plain lists, Document structure +@section Drawers +@cindex drawers +@cindex visibility cycling, drawers + +Sometimes you want to keep information associated with an entry, but you +normally don't want to see it. For this, Org-mode has @emph{drawers}. +Drawers need to be configured with the variable +@code{org-drawers}@footnote{You can define drawers on a per-file basis +with a line like @code{#+DRAWERS: HIDDEN PROPERTIES STATE}}. Drawers +look like this: + +@example +** This is a headline + Still outside the drawer + :DRAWERNAME: + This is inside the drawer. + :END: + After the drawer. +@end example + +Visibility cycling (@pxref{Visibility cycling}) on the headline will +hide and show the entry, but keep the drawer collapsed to a single line. +In order to look inside the drawer, you need to move the cursor to the +drawer line and press @key{TAB} there. Org-mode uses a drawer for +storing properties (@pxref{Properties and columns}). + +@node orgstruct-mode, , Drawers, Document structure +@section The Orgstruct minor mode +@cindex orgstruct-mode +@cindex minor mode for structure editing + +If you like the intuitive way the Org-mode structure editing and list +formatting works, you might want to use these commands in other modes +like text-mode or mail-mode as well. The minor mode Orgstruct-mode +makes this possible. You can always toggle the mode with @kbd{M-x +orgstruct-mode}. To turn it on by default, for example in mail mode, +use + +@lisp +(add-hook 'mail-mode-hook 'turn-on-orgstruct) +@end lisp + +When this mode is active and the cursor is on a line that looks to +Org-mode like a headline of the first line of a list item, most +structure editing commands will work, even if the same keys normally +have different functionality in the major mode you are using. If the +cursor is not in one of those special lines, Orgstruct-mode lurks +silently in the shadow. + @node Tables, Hyperlinks, Document structure, Top @chapter Tables @cindex tables @cindex editing tables -Org-mode has a very fast and intuitive table editor built-in. -Spreadsheet-like calculations are supported in connection with the -Emacs @file{calc} package. +Org-mode comes with a fast and intuitive table editor. Spreadsheet-like +calculations are supported in connection with the Emacs @file{calc} +package +@ifinfo +(@pxref{Top,Calc,,calc,Gnu Emacs Calculator Manual}). +@end ifinfo +@ifnotinfo +(see the Emacs Calculator manual for more information about the Emacs +calculator). +@end ifnotinfo @menu * Built-in table editor:: Simple tables -* Narrow columns:: Stop wasting space in tables +* Narrow columns:: Stop wasting space in tables +* Column groups:: Grouping to trigger vertical lines * orgtbl-mode:: The table editor as minor mode * The spreadsheet:: The table editor has spreadsheet capabilities. @end menu @@ -1087,9 +1293,9 @@ Emacs @file{calc} package. @cindex table editor, built-in Org-mode makes it easy to format tables in plain ASCII. Any line with -@samp{|} as the first non-white character is considered part of a -table. @samp{|} is also the column separator. A table might look -like this: +@samp{|} as the first non-whitespace character is considered part of a +table. @samp{|} is also the column separator. A table might look like +this: @example | Name | Phone | Age | @@ -1130,9 +1336,12 @@ unpredictable for you, configure the variables @item C-c | Convert the active region to table. If every line contains at least one TAB character, the function assumes that the material is tab separated. +If every line contains a comma, comma-separated values (CSV) are assumed. If not, lines are split at whitespace into fields. You can use a prefix -argument to indicate the minimum number of consecutive spaces required -to identify a field separator (default: just one).@* +argument to force a specific separator: @kbd{C-u} forces CSV, @kbd{C-u +C-u} forces TAB, and a numeric argument N indicates that at least N +consequtive spaces, or alternatively a TAB will be the separator. +@* If there is no active region, this command creates an empty Org-mode table. But it's easier just to start typing, like @kbd{|Name|Phone|Age @key{RET} |- @key{TAB}}. @@ -1141,16 +1350,16 @@ table. But it's easier just to start typing, like @kindex C-c C-c @item C-c C-c Re-align the table without moving the cursor. - +@c @kindex @key{TAB} @item @key{TAB} Re-align the table, move to the next field. Creates a new row if necessary. - +@c @kindex S-@key{TAB} @item S-@key{TAB} Re-align, move to previous field. - +@c @kindex @key{RET} @item @key{RET} Re-align the table and move down to next row. Creates a new row if @@ -1163,34 +1372,34 @@ NEWLINE, so it can be used to split a table. @item M-@key{left} @itemx M-@key{right} Move the current column left/right. - +@c @kindex M-S-@key{left} @item M-S-@key{left} Kill the current column. - +@c @kindex M-S-@key{right} @item M-S-@key{right} Insert a new column to the left of the cursor position. - +@c @kindex M-@key{up} @kindex M-@key{down} @item M-@key{up} @itemx M-@key{down} Move the current row up/down. - +@c @kindex M-S-@key{up} @item M-S-@key{up} Kill the current row or horizontal line. - +@c @kindex M-S-@key{down} @item M-S-@key{down} Insert a new row above (with arg: below) the current row. - +@c @kindex C-c - @item C-c - Insert a horizontal line below current row. With prefix arg, the line is created above the current line. - +@c @kindex C-c ^ @item C-c ^ Sort the table lines in the region. The position of point indicates the @@ -1209,10 +1418,12 @@ argument, alphabetic sorting will be case-sensitive. Copy a rectangular region from a table to a special clipboard. Point and mark determine edge fields of the rectangle. The process ignores horizontal separator lines. +@c @kindex C-c C-x C-w @item C-c C-x C-w Copy a rectangular region from a table to a special clipboard, and blank all fields in the rectangle. So this is the ``cut'' operation. +@c @kindex C-c C-x C-y @item C-c C-x C-y Paste a rectangular region into a table. @@ -1220,8 +1431,11 @@ The upper right corner ends up in the current field. All involved fields will be overwritten. If the rectangle does not fit into the present table, the table is enlarged as needed. The process ignores horizontal separator lines. +@c @kindex C-c C-q +@kindex M-@key{RET} @item C-c C-q +@itemx M-@kbd{RET} Wrap several fields in a column like a paragraph. If there is an active region, and both point and mark are in the same column, the text in the column is wrapped to minimum width for the given number of lines. A @@ -1235,7 +1449,6 @@ above. @tsubheading{Calculations} @cindex formula, in tables @cindex calculations, in tables - @cindex region, active @cindex active region @cindex transient-mark-mode @@ -1244,7 +1457,7 @@ above. Sum the numbers in the current column, or in the rectangle defined by the active region. The result is shown in the echo area and can be inserted with @kbd{C-y}. - +@c @kindex S-@key{RET} @item S-@key{RET} When current field is empty, copy from first non-empty field above. @@ -1261,24 +1474,23 @@ Edit the current field in a separate window. This is useful for fields that are not fully visible (@pxref{Narrow columns}). When called with a @kbd{C-u} prefix, just make the full field visible, so that it can be edited in place. - -@kindex C-c @key{TAB} -@item C-c @key{TAB} -This is an alias for @kbd{C-u C-c `} to make the current field fully -visible. - +@c @item M-x org-table-import Import a file as a table. The table should be TAB- or whitespace -separated. Useful, for example, to import an Excel table or data from a -database, because these programs generally can write TAB-separated text -files. This command works by inserting the file into the buffer and -then converting the region to a table. Any prefix argument is passed on -to the converter, which uses it to determine the separator. - +separated. Useful, for example, to import a spreadsheet table or data +from a database, because these programs generally can write +TAB-separated text files. This command works by inserting the file into +the buffer and then converting the region to a table. Any prefix +argument is passed on to the converter, which uses it to determine the +separator. +@item C-c | +Tables can also be imported by pasting tabular text into the org-mode +buffer, selecting the pasted text with @kbd{C-x C-x} and then using the +@kbd{C-c |} command (see above under @i{Creation and conversion}. +@c @item M-x org-table-export Export the table as a TAB-separated file. Useful for data exchange with, -for example, Excel or database programs. - +for example, spreadsheet or database programs. @end table If you don't like the automatic table editor because it gets in your @@ -1292,7 +1504,7 @@ it off with @noindent Then the only table command that still works is @kbd{C-c C-c} to do a manual re-align. -@node Narrow columns, orgtbl-mode, Built-in table editor, Tables +@node Narrow columns, Column groups, Built-in table editor, Tables @section Narrow columns @cindex narrow columns in tables @@ -1320,7 +1532,7 @@ value. @noindent Fields that are wider become clipped and end in the string @samp{=>}. Note that the full text is still in the buffer, it is only invisible. -To see the full text, hold the mouse over the field - a tooltip window +To see the full text, hold the mouse over the field - a tool-tip window will show the full content. To edit such a field, use the command @kbd{C-c `} (that is @kbd{C-c} followed by the backquote). This will open a new window with the full field. Edit it and finish with @kbd{C-c @@ -1338,7 +1550,42 @@ on a per-file basis with: #+STARTUP: noalign @end example -@node orgtbl-mode, The spreadsheet, Narrow columns, Tables +@node Column groups, orgtbl-mode, Narrow columns, Tables +@section Column groups +@cindex grouping columns in tables + +When Org-mode exports tables, it does so by default without vertical +lines because that is visually more satisfying in general. Occasionally +however, vertical lines can be useful to structure a table into groups +of columns, much like horizontal lines can do for groups of rows. In +order to specify column groups, you can use a special row where the +first field contains only @samp{/}. The further fields can either +contain @samp{<} to indicate that this column should start a group, +@samp{>} to indicate the end of a column, or @samp{<>} to make a column +a group of its own. Boundaries between colum groups will upon export be +marked with vertical lines. Here is an example: + +@example +| | N | N^2 | N^3 | N^4 | sqrt(n) | sqrt[4](N) | +|---+----+-----+-----+-----+---------+------------| +| / | <> | < | | > | < | > | +| # | 1 | 1 | 1 | 1 | 1 | 1 | +| # | 2 | 4 | 8 | 16 | 1.4142 | 1.1892 | +| # | 3 | 9 | 27 | 81 | 1.7321 | 1.3161 | +|---+----+-----+-----+-----+---------+------------| +#+TBLFM: $3=$2^2::$4=$2^3::$5=$2^4::$6=sqrt($2)::$7=sqrt(sqrt(($2)) +@end example + +It is also sufficient to just insert the colum group starters after +every vertical line you'd like to have: + +@example +| N | N^2 | N^3 | N^4 | sqrt(n) | sqrt[4](N) | +|----+-----+-----+-----+---------+------------| +| / | < | | | < | | +@end example + +@node orgtbl-mode, The spreadsheet, Column groups, Tables @section The Orgtbl minor mode @cindex orgtbl-mode @cindex minor mode for tables @@ -1355,8 +1602,8 @@ example in mail mode, use Furthermore, with some special setup, it is possible to maintain tables in arbitrary syntax with Orgtbl-mode. For example, it is possible to -construct LaTeX tables with the underlying ease and power of -Orgtbl-mode, including spreadsheet capabulities. For details, see +construct La@TeX{} tables with the underlying ease and power of +Orgtbl-mode, including spreadsheet capabilities. For details, see @ref{Tables in arbitrary syntax}. @node The spreadsheet, , orgtbl-mode, Tables @@ -1367,7 +1614,12 @@ Orgtbl-mode, including spreadsheet capabulities. For details, see The table editor makes use of the Emacs @file{calc} package to implement spreadsheet-like capabilities. It can also evaluate Emacs Lisp forms to -derive fields from other fields. +derive fields from other fields. While fully featured, Org-mode's +implementation is not identical to other spreadsheets. For example, +Org-mode knows the concept of a @emph{column formula} that will be +applied to all non-header fields in a column without having to copy the +formula to each relevant field. + @menu * References:: How to refer to another field or range * Formula syntax for Calc:: Using Calc to compute stuff @@ -1387,17 +1639,26 @@ To compute fields in the table from other fields, formulas must reference other fields or ranges. In Org-mode, fields can be referenced by name, by absolute coordinates, and by relative coordinates. To find out what the coordinates of a field are, press @kbd{C-c ?} in that -field. +field, or press @kbd{C-c @}} to toggle the display of a grid. @subsubheading Field references @cindex field references @cindex references, to fields -Formulas can reference the value of another field with the operator +Formulas can reference the value of another field in two ways. Like in +any other spreadsheet, you may reference fields with a letter/number +combination like @code{B3}, meaning the 2nd field in the 3rd row. +@c Such references are always fixed to that field, they don't change +@c when you copy and paste a formula to a different field. So +@c Org-mode's @code{B3} behaves like @code{$B$3} in other spreadsheets. + +@noindent +Org-mode also uses another, more general operator that looks like this: @example @@row$column @end example +@noindent Column references can be absolute like @samp{1}, @samp{2},...@samp{N}, or relative to the current column like @samp{+1} or @samp{-2}. @@ -1405,30 +1666,34 @@ The row specification only counts data lines and ignores horizontal separator lines (hlines). You can use absolute row numbers @samp{1}...@samp{N}, and row numbers relative to the current row like @samp{+3} or @samp{-1}. Or specify the row relative to one of the -hlines: @samp{I} refers to the first hline, @samp{II} to the second etc. -@samp{-I} refers to the first such line above the current line, -@samp{+I} to the first such line below the current line. You can also -write @samp{III+2} which is the second data line after the third hline -in the table. Relative row numbers like @samp{-3} will not cross hlines -if the current line is too close to the hline. Instead, the value -directly at the hline is used. +hlines: @samp{I} refers to the first hline@footnote{Note that only +hlines are counted that @emph{separate} table lines. If the table +starts with a hline above the header, it does not count.}, @samp{II} to +the second etc. @samp{-I} refers to the first such line above the +current line, @samp{+I} to the first such line below the current line. +You can also write @samp{III+2} which is the second data line after the +third hline in the table. Relative row numbers like @samp{-3} will not +cross hlines if the current line is too close to the hline. Instead, +the value directly at the hline is used. @samp{0} refers to the current row and column. Also, if you omit either the column or the row part of the reference, the current -row/column is implied. +row/column is implied. -Org-mode's references with @emph{positive} numbers correspond to fixed -references in other spreadsheet programs. For example, @code{@@3$28} -corresponds to @code{$AB$3}. Org-mode's references with @emph{negative} -numbers behave similar to non-fixed references in other spreadsheet -programs, because when the same formula is used in several fields, -different fields are referenced each time. +Org-mode's references with @emph{unsigned} numbers are fixed references +in the sense that if you use the same reference in the formula for two +different fields, the same field will be referenced each time. +Org-mode's references with @emph{signed} numbers are floating +references because the same reference operator can reference different +fields depending on the field being calculated by the formula. Here are a few examples: @example @@2$3 @r{2nd row, 3rd column} +C2 @r{same as previous} $5 @r{column 5 in the current row} +E& @r{same as previous} @@2 @r{current column, row 2} @@-1$-3 @r{the field one row up, three columns to the left} @@-I$2 @r{field just under hline above current row, column 2} @@ -1449,6 +1714,7 @@ format at least for the first field (i.e the reference must start with $1..$3 @r{First three fields in the current row.} $P..$Q @r{Range, using column names (see under Advanced)} @@2$1..@@4$3 @r{6 fields between these two fields.} +A2..C4 @r{Same as above.} @@-1$-2..@@-1 @r{3 numbers from the column to the left, 2 up to current row} @end example @@ -1466,12 +1732,29 @@ see the @samp{E} mode switch below). If there are no non-empty fields, @samp{$name} is interpreted as the name of a column, parameter or constant. Constants are defined globally through the variable -@code{org-table-formula-constants}. If you have the -@file{constants.el} package, it will also be used to resolve -constants, including natural constants like @samp{$h} for Planck's -constant, and units like @samp{$km} for kilometers. Column names and -parameters can be specified in special table lines. These are -described below, see @ref{Advanced features}. +@code{org-table-formula-constants}, and locally (for the file) through a +line like + +@example +#+CONSTANTS: c=299792458. pi=3.14 eps=2.4e-6 +@end example + +@noindent +Also properties (@pxref{Properties and columns}) can be used as +constants in table formulas: For a property @samp{:Xyz:} use the name +@samp{$PROP_Xyz}, and the property will be searched in the current +outline entry and in the hierarchy above it. If you have the +@file{constants.el} package, it will also be used to resolve constants, +including natural constants like @samp{$h} for Planck's constant, and +units like @samp{$km} for kilometers@footnote{@file{Constant.el} can +supply the values of constants in two different unit systems, @code{SI} +and @code{cgs}. Which one is used depends on the value of the variable +@code{constants-unit-system}. You can use the @code{#+STARTUP} options +@code{constSI} and @code{constcgs} to set this value for the current +buffer.}. Column names and parameters can be specified in special table +lines. These are described below, see @ref{Advanced features}. All +names must start with a letter, and further consist of letters and +numbers. @node Formula syntax for Calc, Formula syntax for Lisp, References, The spreadsheet @subsection Formula syntax for Calc @@ -1485,6 +1768,7 @@ non-standard convention that @samp{/} has lower precedence than evaluation by @code{calc-eval} (@pxref{Calling Calc from Your Programs,calc-eval,Calling calc from Your Lisp Programs,calc,GNU Emacs Calc Manual}), +@c FIXME: The link to the calc manual in HTML does not work. variable substitution takes place according to the rules described above. @cindex vectors, in table calculations The range vectors can be directly fed into the calc vector functions @@ -1518,7 +1802,7 @@ reformat the final result. A few examples: $1+$2 @r{Sum of first and second field} $1+$2;%.2f @r{Same, format result to two decimals} exp($2)+exp($1) @r{Math functions can be used} -$;%.1f @r{Reformat current cell to 1 decimal} +$0;%.1f @r{Reformat current cell to 1 decimal} ($3-32)*5/9 @r{Degrees F -> C conversion} $c/$1/$cm @r{Hz -> cm conversion, using @file{constants.el}} tan($1);Dp3s1 @r{Compute in degrees, precision 3, display SCI 1} @@ -1528,21 +1812,34 @@ vmean($2..$7);EN @r{Same, but treat empty fields as 0} taylor($3,x=7,2) @r{taylor series of $3, at x=7, second degree} @end example +Calc also contains a complete set of logical operations. For example + +@example +if($1<20,teen,string("")) @r{``teen'' if age $1 less than 20, else empty} +@end example + @node Formula syntax for Lisp, Field formulas, Formula syntax for Calc, The spreadsheet @subsection Emacs Lisp forms as formulas @cindex Lisp forms, as table formulas It is also possible to write a formula in Emacs Lisp; this can be useful -for string manipulation and control structures. If a formula starts -with a single quote followed by an opening parenthesis, then it is -evaluated as a lisp form. The evaluation should return either a string -or a number. Just as with @file{calc} formulas, you can specify modes -and a printf format after a semicolon. A reference will be replaced -with a string (in double quotes) containing the field. If you provide -the @samp{N} mode switch, all referenced elements will be numbers. -Ranges are inserted as space-separated fields, so you can embed them in -list or vector syntax. A few examples, note how the @samp{N} mode is -used when we do computations in lisp. +for string manipulation and control structures, if the Calc's +functionality is not enough. If a formula starts with a single quote +followed by an opening parenthesis, then it is evaluated as a lisp form. +The evaluation should return either a string or a number. Just as with +@file{calc} formulas, you can specify modes and a printf format after a +semicolon. With Emacs Lisp forms, you need to be concious about the way +field references are interpolated into the form. By default, a +reference will be interpolated as a Lisp string (in double quotes) +containing the field. If you provide the @samp{N} mode switch, all +referenced elements will be numbers (non-number fields will be zero) and +interpolated as Lisp numbers, without quotes. If you provide the +@samp{L} flag, all fields will be interpolated literally, without quotes. +I.e., if you want a reference to be interpreted as a string by the Lisp +form, enclode the reference operator itself in double quotes, like +@code{"$3"}. Ranges are inserted as space-separated fields, so you can +embed them in list or vector syntax. A few examples, note how the +@samp{N} mode is used when we do computations in lisp. @example @r{Swap the first two characters of the content of column 1} @@ -1567,12 +1864,11 @@ evaluated, and the current field replaced with the result. Formulas are stored in a special line starting with @samp{#+TBLFM:} directly below the table. If you typed the equation in the 4th field of the 3rd data line in the table, the formula will look like -@samp{@@3$2=$1+$2}. When inserting/deleting/swapping column and rows +@samp{@@3$4=$1+$2}. When inserting/deleting/swapping column and rows with the appropriate commands, @i{absolute references} (but not relative -ones) in stored formulas are modified in order to -still reference the same field. Of cause this is not true if you edit -the table structure with normal editing commands - then you must go and -fix equations yourself. +ones) in stored formulas are modified in order to still reference the +same field. Of cause this is not true if you edit the table structure +with normal editing commands - then you must fix the equations yourself. Instead of typing an equation into the field, you may also use the following command @@ -1593,7 +1889,9 @@ it to the current field and stores it. Often in a table, the same formula should be used for all fields in a particular column. Instead of having to copy the formula to all fields in that column, org-mode allows to assign a single formula to an entire -column. +column. If the table contains horizontal separator hlines, everything +before the first such line is considered part of the table @emph{header} +and will not be modified by column formulas. To assign a formula to a column, type it directly into any field in the column, preceded by an equal sign, like @samp{=$1+$2}. When you press @@ -1626,7 +1924,11 @@ will apply it to that many consecutive fields in the current column. You can edit individual formulas in the minibuffer or directly in the field. Org-mode can also prepare a special buffer with all active -formulas of a table. +formulas of a table. When offering a formula for editing, Org-mode +converts references to the standard format (like @code{B3} or @code{D&}) +if possible. If you prefer to only work with the internal format (like +@code{@@3$2} or @code{$4}), configure the variable +@code{org-table-use-standard-references}. @table @kbd @kindex C-c = @@ -1645,21 +1947,36 @@ minibuffer is that you can use the command @kbd{C-c ?}. @item C-c ? While editing a formula in a table field, highlight the field(s) referenced by the reference at the cursor position in the formula. +@kindex C-c @} +@item C-c @} +Toggle the display of row and column numbers for a table, using +overlays. These are updated each time the table is aligned, you can +force it with @kbd{C-c C-c}. +@kindex C-c @{ +@item C-c @{ +Toggle the formula debugger on and off. See below. @kindex C-c ' @item C-c ' Edit all formulas for the current table in a special buffer, where the -formulas will be displayed one per line. +formulas will be displayed one per line. If the current field has an +active formula, the cursor in the formula editor will mark it. While inside the special buffer, Org-mode will automatically highlight any field or range reference at the cursor position. You may edit, remove and add formulas, and use the following commands: @table @kbd @kindex C-c C-c +@kindex C-x C-s @item C-c C-c -Exit the buffer and store the modified formulas. With @kbd{C-u} prefix, -also apply the new formulas to the entire table. +@itemx C-x C-s +Exit the formula editor and store the modified formulas. With @kbd{C-u} +prefix, also apply the new formulas to the entire table. @kindex C-c C-q @item C-c C-q -Exit the buffer without installing changes. +Exit the formula editor without installing changes. +@kindex C-c C-r +@item C-c C-r +Toggle all references in the formula editor between standard (like +@code{B3}) and internal (like @code{@@3$2}). @kindex @key{TAB} @item @key{TAB} Pretty-print or indent lisp formula at point. When in a line containing @@ -1671,23 +1988,25 @@ formula, @key{TAB} re-indents just like in Emacs-lisp-mode. Complete Lisp symbols, just like in Emacs-lisp-mode. @kindex S-@key{up} @kindex S-@key{down} -@item S-@key{up}/@key{down} -Move the reference line in the Org-mode buffer up and down. This is -important for highlighting the references of column formulas for -different rows. +@kindex S-@key{left} +@kindex S-@key{right} +@item S-@key{up}/@key{down}/@key{left}/@key{right} +Shift the reference at point. For example, if the reference is +@code{B3} and you press @kbd{S-@key{right}}, it will become @code{C3}. +This also works for relative references, and for hline references. +@kindex M-S-@key{up} +@kindex M-S-@key{down} +@item M-S-@key{up}/@key{down} +Move the test line for column formulas in the Org-mode buffer up and +down. @kindex M-@key{up} @kindex M-@key{down} @item M-@key{up}/@key{down} Scroll the window displaying the table. -@end table @kindex C-c @} @item C-c @} -Toggle the display of row and column numbers for a table, using -overlays. These are uptated each time the table is aligned, you can -force it with @kbd{C-c C-c}. -@kindex C-c @{ -@item C-c @{ -Toggle the formula debugger on and off. See below. +Turn the coordinate grid in the table on and off. +@end table @end table Making a table field blank does not remove the formula associated with @@ -1708,8 +2027,8 @@ When the evaluation of a formula leads to an error, the field content becomes the string @samp{#ERROR}. If you would like see what is going on during variable substitution and calculation in order to find a bug, turn on formula debugging in the @code{Tbl} menu and repeat the -calculation, for example by pressing @kbd{C-c = @key{RET}} in a field. -Detailed information will be displayed. +calculation, for example by pressing @kbd{C-u C-u C-c = @key{RET}} in a +field. Detailed information will be displayed. @node Updating the table, Advanced features, Editing and debugging formulas, The spreadsheet @subsection Updating the Table @@ -1728,22 +2047,23 @@ following commands: @item C-c * Recalculate the current row by first applying the stored column formulas from left to right, and all field formulas in the current row. - +@c @kindex C-u C-c * @item C-u C-c * @kindex C-u C-c C-c @itemx C-u C-c C-c Recompute the entire table, line by line. Any lines before the first hline are left alone, assuming that these are part of the table header. - +@c @kindex C-u C-u C-c * +@kindex C-u C-u C-c C-c @item C-u C-u C-c * +@itemx C-u C-u C-c C-c Iterate the table by recomputing it until no further changes occur. This may be necessary if some computed fields use the value of other fields that are computed @i{later} in the calculation sequence. @end table - @node Advanced features, , Updating the table, The spreadsheet @subsection Advanced features @@ -1829,8 +2149,8 @@ Do not export this line. Useful for lines that contain the narrowing Finally, just to whet your appetite on what can be done with the fantastic @file{calc} package, here is a table that computes the Taylor -series of degree @code{n} at location @code{x} for a couple of functions -(homework: try that with Excel :-) +series of degree @code{n} at location @code{x} for a couple of +functions. @example @group @@ -1852,18 +2172,18 @@ series of degree @code{n} at location @code{x} for a couple of functions @chapter Hyperlinks @cindex hyperlinks -Just like HTML, Org-mode provides links inside a file, and external -links to other files, Usenet articles, emails, and much more. +Like HTML, Org-mode provides links inside a file, external links to +other files, Usenet articles, emails, and much more. @menu * Link format:: How links in Org-mode are formatted * Internal links:: Links to other places in the current file * External links:: URL-like links to the world * Handling links:: Creating, inserting and following +* Using links outside Org-mode:: Linking from my C source code? * Link abbreviations:: Shortcuts for writing complex links * Search options:: Linking to a specific location * Custom searches:: When the default search is not enough -* Remember:: Org-trees store quick notes @end menu @node Link format, Internal links, Hyperlinks, Hyperlinks @@ -1875,7 +2195,7 @@ Org-mode will recognize plain URL-like links and activate them as clickable links. The general link format, however, looks like this: @example -[[link][description]] @r{or alternatively} [[link]] +[[link][description]] @r{or alternatively} [[link]] @end example Once a link in the buffer is complete (all brackets present), Org-mode @@ -1917,8 +2237,8 @@ convenient to put them into a comment line. For example @noindent In HTML export (@pxref{HTML export}), such targets will become named anchors for direct access through @samp{http} links@footnote{Note -that text before the first headline will never be exported, so the first -such target must be after the first headline.}. +that text before the first headline is usually not exported, so the +first such target should be after the first headline.}. If no dedicated target exists, Org-mode will search for the words in the link. In the above example the search would be for @samp{my target}. @@ -1954,15 +2274,15 @@ earlier. @cindex targets, radio @cindex links, radio targets -You can configure Org-mode to link any occurrences of certain target -names in normal text. So without explicitly creating a link, the text -connects to the target radioing its position. Radio targets are -enclosed by triple angular brackets. For example, a target -@samp{<<>>} causes each occurrence of @samp{my target} in -normal text to become activated as a link. The Org-mode file is -scanned automatically for radio targets only when the file is first -loaded into Emacs. To update the target list during editing, press -@kbd{C-c C-c} with the cursor on or at a target. +Org-mode can automatically turn any occurrences of certain target names +in normal text into a link. So without explicitly creating a link, the +text connects to the target radioing its position. Radio targets are +enclosed by triple angular brackets. For example, a target @samp{<<>>} causes each occurrence of @samp{my target} in normal text to +become activated as a link. The Org-mode file is scanned automatically +for radio targets only when the file is first loaded into Emacs. To +update the target list during editing, press @kbd{C-c C-c} with the +cursor on or at a target. @node External links, Handling links, Internal links, Hyperlinks @section External links @@ -1971,6 +2291,7 @@ loaded into Emacs. To update the target list during editing, press @cindex links, external @cindex GNUS links @cindex BBDB links +@cindex IRC links @cindex URL links @cindex file links @cindex VM links @@ -1983,20 +2304,20 @@ loaded into Emacs. To update the target list during editing, press @cindex elisp links Org-mode supports links to files, websites, Usenet and email messages, -and BBDB database entries. External links are URL-like locators. They -start with a short identifying string followed by a colon. There can be -no space after the colon. The following list shows examples for each -link type. +BBDB database entries and links to both IRC conversations and their +logs. External links are URL-like locators. They start with a short +identifying string followed by a colon. There can be no space after +the colon. The following list shows examples for each link type. @example http://orgmode.org/ @r{on the web} file:/home/dominik/images/jupiter.jpg @r{file, absolute path} file:papers/last.pdf @r{file, relative path} news:comp.emacs @r{Usenet link} -mailto:adent@@galaxy.net @r{Mail link} +mailto:adent@@galaxy.net @r{Mail link} vm:folder @r{VM folder link} vm:folder#id @r{VM message link} -vm://myself@@some.where.org/folder#id @r{VM on remote machine} +vm://myself@@some.where.org/folder#id @r{VM on remote machine} wl:folder @r{WANDERLUST folder link} wl:folder#id @r{WANDERLUST message link} mhe:folder @r{MH-E folder link} @@ -2006,6 +2327,7 @@ rmail:folder#id @r{RMAIL message link} gnus:group @r{GNUS group link} gnus:group#id @r{GNUS article link} bbdb:Richard Stallman @r{BBDB link} +irc:/irc.com/#emacs/bob @r{IRC link} shell:ls *.org @r{A shell command} elisp:(find-file-other-frame "Elisp.org") @r{An elisp form to evaluate} @end example @@ -2032,7 +2354,7 @@ as links. If spaces must be part of the link (for example in @samp{bbdb:Richard Stallman}), or if you need to remove ambiguities about the end of the link, enclose them in angular brackets. -@node Handling links, Link abbreviations, External links, Hyperlinks +@node Handling links, Using links outside Org-mode, External links, Hyperlinks @section Handling links @cindex links, handling @@ -2046,19 +2368,24 @@ insert it into an org-mode file, and to follow the link. Store a link to the current location. This is a @emph{global} command which can be used in any buffer to create a link. The link will be stored for later insertion into an Org-mode buffer (see below). For -Org-mode files, if there is a @samp{<>} at the cursor, the link -points to the target. Otherwise it points to the current headline. For -VM, RMAIL, WANDERLUST, MH-E, GNUS and BBDB buffers, the link will -indicate the current article/entry. For W3 and W3M buffers, the link -goes to the current URL. For any other files, the link will point to -the file, with a search string (@pxref{Search options}) pointing to the -contents of the current line. If there is an active region, the -selected words will form the basis of the search string. If the -automatically created link is not working correctly or accurately -enough, you can write custom functions to select the search string and -to do the search for particular file types - see @ref{Custom searches}. -The key binding @kbd{C-c l} is only a suggestion - see @ref{Installation}. - +Org-mode files, if there is a @samp{<>} at the cursor, the +link points to the target. Otherwise it points to the current +headline. For VM, RMAIL, WANDERLUST, MH-E, GNUS and BBDB buffers, the +link will indicate the current article/entry. For W3 and W3M buffers, +the link goes to the current URL. For IRC links, if you set the +variable @code{org-irc-link-to-logs} to non-nil then @kbd{C-c l} will +store a @samp{file:/} style link to the relevant point in the logs for +the current conversation. Otherwise an @samp{irc:/} style link to the +user/channel/server under the point will be stored. For any other +files, the link will point to the file, with a search string +(@pxref{Search options}) pointing to the contents of the current line. +If there is an active region, the selected words will form the basis +of the search string. If the automatically created link is not +working correctly or accurately enough, you can write custom functions +to select the search string and to do the search for particular file +types - see @ref{Custom searches}. The key binding @kbd{C-c l} is +only a suggestion - see @ref{Installation}. +@c @kindex C-c C-l @cindex link completion @cindex completion, of links @@ -2068,24 +2395,27 @@ Insert a link. This prompts for a link to be inserted into the buffer. You can just type a link, using text for an internal link, or one of the link type prefixes mentioned in the examples above. All links stored during the current session are part of the history for this prompt, so -you can access them with @key{up} and @key{down}, or with -completion@footnote{After insertion of a stored link, the link will be -removed from the list of stored links. To keep it in the list later -use, use a triple @kbd{C-u} prefix to @kbd{C-c C-l}, or configure the -option @code{org-keep-stored-link-after-insertion}.}. The link will be -inserted into the buffer, along with a descriptive text. If some text -was selected when this command is called, the selected text becomes the -default description.@* Note that you don't have to use this command to -insert a link. Links in Org-mode are plain text, and you can type or -paste them straight into the buffer. By using this command, the links -are automatically enclosed in double brackets, and you will be asked for -the optional descriptive text. - +you can access them with @key{up} and @key{down} (or @kbd{M-p/n}). +Completion, on the other hand, will help you to insert valid link +prefixes like @samp{http:} or @samp{ftp:}, including the prefixes +defined through link abbreviations (@pxref{Link abbreviations}). The +link will be inserted into the buffer@footnote{After insertion of a +stored link, the link will be removed from the list of stored links. To +keep it in the list later use, use a triple @kbd{C-u} prefix to @kbd{C-c +C-l}, or configure the option +@code{org-keep-stored-link-after-insertion}.}, along with a descriptive +text. If some text was selected when this command is called, the +selected text becomes the default description.@* Note that you don't +have to use this command to insert a link. Links in Org-mode are plain +text, and you can type or paste them straight into the buffer. By using +this command, the links are automatically enclosed in double brackets, +and you will be asked for the optional descriptive text. +@c @c If the link is a @samp{file:} link and @c the linked file is located in the same directory as the current file or @c a subdirectory of it, the path of the file will be inserted relative to @c the current directory. - +@c @kindex C-u C-c C-l @cindex file name completion @cindex completion, of file names @@ -2098,11 +2428,11 @@ directory or in a subdirectory of it, or if the path is written relative to the current directory using @samp{../}. Otherwise an absolute path is used, if possible with @samp{~/} for your home directory. You can force an absolute path with two @kbd{C-u} prefixes. - -@item C-c C-l @r{with cursor on existing link} +@c +@item C-c C-l @r{(with cursor on existing link)} When the cursor is on an existing link, @kbd{C-c C-l} allows you to edit the link and description parts of the link. - +@c @cindex following links @kindex C-c C-o @item C-c C-o @@ -2118,26 +2448,26 @@ suitable application for local non-text files. Classification of files is based on file extension only. See option @code{org-file-apps}. If you want to override the default application and visit the file with Emacs, use a @kbd{C-u} prefix. - +@c @kindex mouse-2 @kindex mouse-1 @item mouse-2 @itemx mouse-1 On links, @kbd{mouse-2} will open the link just as @kbd{C-c C-o} would. Under Emacs 22, also @kbd{mouse-1} will follow a link. - +@c @kindex mouse-3 @item mouse-3 Like @kbd{mouse-2}, but force file links to be opened with Emacs, and internal links to be displayed in another window@footnote{See the variable @code{org-display-internal-link-with-indirect-buffer}}. - +@c @cindex mark ring @kindex C-c % @item C-c % Push the current position onto the mark ring, to be able to return easily. Commands following an internal link do this automatically. - +@c @cindex links, returning to @kindex C-c & @item C-c & @@ -2145,7 +2475,7 @@ Jump back to a recorded position. A position is recorded by the commands following internal links, and by @kbd{C-c %}. Using this command several times in direct succession moves through a ring of previously recorded positions. - +@c @kindex C-c C-x C-n @kindex C-c C-x C-p @cindex links, finding next/previous @@ -2163,7 +2493,20 @@ to @kbd{C-n} and @kbd{C-p} @end lisp @end table -@node Link abbreviations, Search options, Handling links, Hyperlinks +@node Using links outside Org-mode, Link abbreviations, Handling links, Hyperlinks +@section Using links outside Org-mode + +You can insert and follow links that have Org-mode syntax not only in +Org-mode, but in any Emacs buffer. For this, you should create two +global commands, like this (please select suitable global keys +yourself): + +@lisp +(global-set-key "\C-c L" 'org-insert-link-global) +(global-set-key "\C-c o" 'org-open-at-point-global) +@end lisp + +@node Link abbreviations, Search options, Using links outside Org-mode, Hyperlinks @section Link abbreviations @cindex link abbreviations @cindex abbreviation, links @@ -2225,7 +2568,7 @@ compatibility, line numbers can also follow a single colon.} colon. For example, when the command @kbd{C-c l} creates a link (@pxref{Handling links}) to a file, it encodes the words in the current line as a search string that can be used to find this line back later when following the -link with @kbd{C-c C-o}. +link with @kbd{C-c C-o}. Here is the syntax of the different ways to attach a search to a file link, together with an explanation: @@ -2262,7 +2605,7 @@ to search the current file. For example, @code{[[file:::find me]]} does a search for @samp{find me} in the current file, just as @samp{[[find me]]} would. -@node Custom searches, Remember, Search options, Hyperlinks +@node Custom searches, , Search options, Hyperlinks @section Custom Searches @cindex custom search strings @cindex search strings, custom @@ -2286,196 +2629,36 @@ an implementation example. Search for @samp{BibTeX links} in the source file. -@node Remember, , Custom searches, Hyperlinks -@section Remember -@cindex @file{remember.el} -Another way to create org entries with links to other files is through -the @i{remember} package by John Wiegley. @i{Remember} lets you store -quick notes with little interruption of your work flow. See -@uref{http://www.emacswiki.org/cgi-bin/wiki/RememberMode} for more -information. The notes produced by @i{Remember} can be stored in -different ways, and Org-mode files are a good target. Org-mode -significantly expands the possibilities of @i{remember}: You may define -templates for different note types, and to associate target files and -headlines with specific templates. It also allows you to select the -location where a note should be stored interactively, on the fly. - -@menu -* Setting up remember:: Some code for .emacs to get things going -* Remember templates:: Define the outline of different note types -* Storing notes:: Directly get the note to where it belongs -@end menu - -@node Setting up remember, Remember templates, Remember, Remember -@subsection Setting up remember - -The following customization will tell @i{remember} to use org files as -target, and to create annotations compatible with Org-mode links. - -@example -(setq org-directory "~/path/to/my/orgfiles/") -(setq org-default-notes-file "~/.notes") -(setq remember-annotation-functions '(org-remember-annotation)) -(setq remember-handler-functions '(org-remember-handler)) -(add-hook 'remember-mode-hook 'org-remember-apply-template) -@end example - -@node Remember templates, Storing notes, Setting up remember, Remember -@subsection Remember templates -@cindex templates, for remember - -In combination with Org-mode, you can use templates to generate -different types of @i{remember} notes. For example, if you would like -to use one template to create general TODO entries, another one for -journal entries, and a third one for collecting random ideas, you could -use: - -@example -(setq org-remember-templates - '((?t "* TODO %?\n %i\n %a" "~/org/TODO.org") - (?j "* %U %?\n\n %i\n %a" "~/org/JOURNAL.org") - (?i "* %^@{Title@}\n %i\n %a" "~/org/JOURNAL.org" "New Ideas"))) -@end example - -@noindent In these entries, the character specifies how to select the -template. The first string specifies the template. Two more (optional) -strings give the file in which, and the headline under which the new -note should be stored. The file defaults to -@code{org-default-notes-file}, the heading to -@code{org-remember-default-headline}. Both defaults help to get to the -storing location quickly, but you can change the location interactively -while storing the note. - -When you call @kbd{M-x remember} (or @kbd{M-x org-remember}) to remember -something, org will prompt for a key to select the template (if you have -more than one template) and then prepare the buffer like -@example -* TODO - [[file:link to where you called remember]] -@end example - -@noindent or - -@example -* [2006-03-21 Tue 15:37] - - [[file:link to where you called remember]] -@end example - -@noindent -During expansion of the template, special @kbd{%}-escapes allow dynamic -insertion of content: -@example -%^@{prompt@} @r{prompt the user for a string and replace this sequence with it.} -%t @r{time stamp, date only} -%T @r{time stamp with date and time} -%u, %U @r{like the above, but inactive time stamps} -%^t @r{like @code{%t}, but prompt for date. Similarly @code{%^T}, @code{%^u}, @code{%^U}} - @r{You may define a prompt like @code{%^@{Birthday@}t}} -%n @r{user name (taken from @code{user-full-name})} -%a @r{annotation, normally the link created with @code{org-store-link}} -%i @r{initial content, the region when remember is called with C-u.} - @r{The entire text will be indented like @code{%i} itself.} -%:keyword @r{specific information for certain link types, see below} -@end example - -@noindent -For specific link types, the following keywords will be defined: - -@example -Link type | Available keywords --------------------+---------------------------------------------- -bbdb | %:name %:company -vm, wl, mh, rmail | %:type %:subject %:message-id - | %:from %:fromname %:fromaddress - | %:to %:toname %:toaddress - | %:fromto @r{(either "to NAME" or "from NAME")@footnote{This will always be the other, not the user. See the variable @code{org-from-is-user-regexp}.}} -gnus | %:group, @r{for messages also all email fields} -w3, w3m | %:url -info | %:file %:node -calendar | %:date" -@end example - -@noindent -If you would like to have the cursor in a specific position after the -template has been expanded: - -@example -%? @r{After completing the template, position cursor here.} -@end example - -@noindent -If you change you mind about which template to use, call -@code{org-remember} in the remember buffer. You may then select a new -template that will be filled with the previoous context information. - -@node Storing notes, , Remember templates, Remember -@subsection Storing notes - -When you are finished preparing a note with @i{remember}, you have to press -@kbd{C-c C-c} to file the note away. The handler first prompts for a -target file - if you press @key{RET}, the value specified for the -template is used. Then the command offers the headings tree of the -selected file, with the cursor position at the default headline (if you -had specified one in the template). You can either immediately press -@key{RET} to get the note placed there. Or you can use vertical cursor -motion (@key{up} and @key{down}) and visibility cycling (@key{TAB}) to -find a better place. Pressing @key{RET} or @key{left} or @key{right} -then leads to the following result. - -@multitable @columnfractions 0.2 0.1 0.7 -@item @b{Cursor position} @tab @b{Key} @tab @b{Note gets inserted} -@item buffer-start @tab @key{RET} @tab as level 2 heading at end of file -@item on headline @tab @key{RET} @tab as sublevel of the heading at cursor -@item @tab @key{left} @tab as same level, before current heading -@item @tab @key{right} @tab as same level, after current heading -@item not on headline @tab @key{RET} - @tab at cursor position, level taken from context. - Or use prefix arg to specify level manually. -@end multitable - -So a fast way to store the note to its default location is to press -@kbd{C-c C-c @key{RET} @key{RET}}. Even shorter would be @kbd{C-u C-c -C-c}, which does the same without even asking for a file or showing the -tree. - -Before inserting the text into a tree, the function ensures that the -text has a headline, i.e. a first line that starts with a @samp{*}. -If not, a headline is constructed from the current date and some -additional data. If the variable @code{org-adapt-indentation} is -non-nil, the entire text is also indented so that it starts in the -same column as the headline (after the asterisks). - - -@node TODO items, Timestamps, Hyperlinks, Top +@node TODO items, Tags, Hyperlinks, Top @chapter TODO items @cindex TODO items -Org-mode does not maintain TODO lists as a separate document. TODO -items are an integral part of the notes file, because TODO items -usually come up while taking notes! With Org-mode, you simply mark -any entry in a tree as being a TODO item. In this way, the -information is not duplicated, and the entire context from which the -item emerged is always present when you check. +Org-mode does not maintain TODO lists as separate documents. Instead, +TODO items are an integral part of the notes file, because TODO items +usually come up while taking notes! With Org-mode, simply mark any +entry in a tree as being a TODO item. In this way, information is not +duplicated, and the entire context from which the TODO item emerged is +always present. -Of course, this technique causes TODO items to be scattered throughout -your file. Org-mode provides methods to give you an overview over all -things you have to do. +Of course, this technique for managing TODO items scatters them +throughout your notes file. Org-mode compensates for this by providing +methods to give you an overview of all the things that you have to do. @menu * TODO basics:: Marking and displaying TODO entries * TODO extensions:: Workflow and assignments +* Progress logging:: Dates and notes for progress * Priorities:: Some things are more important than others -* Breaking down tasks:: Splitting a task into managable pieces +* Breaking down tasks:: Splitting a task into manageable pieces * Checkboxes:: Tick-off lists @end menu @node TODO basics, TODO extensions, TODO items, TODO items @section Basic TODO functionality -Any headline can become a TODO item by starting it with the word TODO, -for example: +Any headline becomes a TODO item when it starts with the word +@samp{TODO}, for example: @example *** TODO Write letter to Sam Fortune @@ -2488,7 +2671,7 @@ The most important commands to work with TODO entries are: @kindex C-c C-t @cindex cycling, of TODO states @item C-c C-t -Rotate the TODO state of the current item between +Rotate the TODO state of the current item among @example ,-> (unmarked) -> TODO -> DONE --. @@ -2497,50 +2680,65 @@ Rotate the TODO state of the current item between The same rotation can also be done ``remotely'' from the timeline and agenda buffers with the @kbd{t} command key (@pxref{Agenda commands}). + +@kindex C-u C-c C-t +@item C-u C-c C-t +Select a specific keyword using completion or (if it has been set up) +the fast selection interface. For the latter, you need to assign keys +to TODO states, see @ref{Per-file keywords} and @ref{Setting tags} for +more information. + @kindex S-@key{right} @kindex S-@key{left} @item S-@key{right} @itemx S-@key{left} -Select the following/preceding TODO state, similar to cycling. Mostly -useful if more than two TODO states are possible (@pxref{TODO extensions}). +Select the following/preceding TODO state, similar to cycling. Useful +mostly if more than two TODO states are possible (@pxref{TODO +extensions}). @kindex C-c C-v +@kindex C-c / t @cindex sparse tree, for TODO @item C-c C-v +@itemx C-c / t View TODO items in a @emph{sparse tree} (@pxref{Sparse trees}). Folds the entire buffer, but shows all TODO items and the headings hierarchy -above them. With prefix arg, show also the DONE entries. With -numerical prefix N, show the tree for the Nth keyword in the variable -@code{org-todo-keywords}. +above them. With prefix arg, search for a specific TODO. You will be +prompted for the keyword, and you can also give a list of keywords like +@code{KWD1|KWD2|...}. With numerical prefix N, show the tree for the +Nth keyword in the variable @code{org-todo-keywords}. With two prefix +args, find all TODO and DONE entries. @kindex C-c a t @item C-c a t -Show the global TODO list. This collects the TODO items from all -agenda files (@pxref{Agenda views}) into a single buffer. The buffer is in -@code{agenda-mode}, so there are commands to examine and manipulate -the TODO entries directly from that buffer (@pxref{Agenda commands}). -@xref{Global TODO list}, for more information. -@c @item @code{org-agenda-include-all-todo} -@c If you would like to have all your TODO items listed as part of your -@c agenda, customize the variable @code{org-agenda-include-all-todo}. +Show the global TODO list. Collects the TODO items from all agenda +files (@pxref{Agenda views}) into a single buffer. The new buffer will +be in @code{agenda-mode}, which provides commands to examine and +manipulate the TODO entries from the new buffer (@pxref{Agenda +commands}). @xref{Global TODO list}, for more information. +@kindex S-M-@key{RET} +@item S-M-@key{RET} +Insert a new TODO entry below the current one. @end table - -@node TODO extensions, Priorities, TODO basics, TODO items +@node TODO extensions, Progress logging, TODO basics, TODO items @section Extended use of TODO keywords @cindex extended TODO keywords -The default implementation of TODO entries is just two states: TODO and -DONE. You can, however, use the TODO feature for more complicated -things by configuring the variables @code{org-todo-keywords} and -@code{org-todo-interpretation}. Using special setup, you can even use -TODO keywords in different ways in different org files. +By default, marked TODO entries have one of only two states: TODO and +DONE. Org-mode allows you to classify TODO items in more complex ways +with @emph{TODO keywords} (stored in @code{org-todo-keywords}). With +special setup, the TODO keyword system can work differently in different +files. Note that @i{tags} are another way to classify headlines in general and TODO items in particular (@pxref{Tags}). @menu * Workflow states:: From TODO to DONE in steps -* TODO types:: I do this, Fred the rest -* Per file keywords:: Different files, different requirements +* TODO types:: I do this, Fred does the rest +* Multiple sets in one file:: Mixing it all, and still finding your way +* Fast access to TODO states:: Single letter selection of a state +* Per-file keywords:: Different files, different requirements +* Faces for TODO keywords:: Highlighting states @end menu @node Workflow states, TODO types, TODO extensions, TODO extensions @@ -2548,77 +2746,159 @@ TODO items in particular (@pxref{Tags}). @cindex TODO workflow @cindex workflow states as TODO keywords -You can use TODO keywords to indicate different states in the process -of working on an item, for example: +You can use TODO keywords to indicate different @emph{sequential} states +in the process of working on an item, for example@footnote{Changing +this variable only becomes effective after restarting Org-mode in a +buffer.}: @lisp -(setq org-todo-keywords '("TODO" "FEEDBACK" "VERIFY" "DONE") - org-todo-interpretation 'sequence) +(setq org-todo-keywords + '((sequence "TODO" "FEEDBACK" "VERIFY" "|" "DONE" "DELEGATED"))) @end lisp +The vertical bar separates the TODO keywords (states that @emph{need +action}) from the DONE states (which need @emph{no further action}. If +you don't provide the separator bar, the last state is used as the DONE +state. @cindex completion, of TODO keywords -Changing these variables only becomes effective in a new Emacs session. -With this setup, the command @kbd{C-c C-t} will cycle an entry from -TODO to FEEDBACK, then to VERIFY, and finally to DONE. You may also -use a prefix argument to quickly select a specific state. For example -@kbd{C-3 C-c C-t} will change the state immediately to VERIFY. -If you define many keywords, you can use in-buffer completion (see -@ref{Completion}) to insert these words into the buffer. Changing a todo -state can be logged with a timestamp, see @ref{Tracking TODO state -changes} for more information. +With this setup, the command @kbd{C-c C-t} will cycle an entry from TODO +to FEEDBACK, then to VERIFY, and finally to DONE and DELEGATED. You may +also use a prefix argument to quickly select a specific state. For +example @kbd{C-3 C-c C-t} will change the state immediately to VERIFY. +Or you can use @kbd{S-left} to go backward through the sequence. If you +define many keywords, you can use in-buffer completion +(@pxref{Completion}) or even a special one-key selection scheme +(@pxref{Fast access to TODO states}) to insert these words into the +buffer. Changing a todo state can be logged with a timestamp, see +@ref{Tracking TODO state changes} for more information. -@node TODO types, Per file keywords, Workflow states, TODO extensions +@node TODO types, Multiple sets in one file, Workflow states, TODO extensions @subsection TODO keywords as types @cindex TODO types @cindex names as TODO keywords @cindex types as TODO keywords The second possibility is to use TODO keywords to indicate different -types of action items. For example, you might want to indicate that -items are for ``work'' or ``home''. If you are into David Allen's -@emph{Getting Things DONE}, you might want to use todo types -@samp{NEXTACTION}, @samp{WAITING}, @samp{MAYBE}. Or, when you work -with several people on a single project, you might want to assign -action items directly to persons, by using their names as TODO -keywords. This would be set up like this: +@emph{types} of action items. For example, you might want to indicate +that items are for ``work'' or ``home''. Or, when you work with several +people on a single project, you might want to assign action items +directly to persons, by using their names as TODO keywords. This would +be set up like this: @lisp -(setq org-todo-keywords '("Fred" "Sara" "Lucy" "Mike" "DONE") - org-todo-interpretation 'type) +(setq org-todo-keywords '((type "Fred" "Sara" "Lucy" "|" "DONE"))) @end lisp -In this case, different keywords do not indicate a sequence, but -rather different types. So it is normally not useful to change from -one type to another. Therefore, in this case the behavior of the -command @kbd{C-c C-t} is changed slightly@footnote{This is also true -for the @kbd{t} command in the timeline and agenda buffers.}. When -used several times in succession, it will still cycle through all -names. But when you return to the item after some time and execute -@kbd{C-c C-t} again, it will switch from each name directly to DONE. -Use prefix arguments or completion to quickly select a specific name. -You can also review the items of a specific TODO type in a sparse tree -by using a numeric prefix to @kbd{C-c C-v}. For example, to see all -things Lucy has to do, you would use @kbd{C-3 C-c C-v}. To collect -Lucy's items from all agenda files into a single buffer, you -would use the prefix arg as well when creating the global todo list: -@kbd{C-3 C-c t}. +In this case, different keywords do not indicate a sequence, but rather +different types. So the normal work flow would be to assign a task to a +person, and later to mark it DONE. Org-mode supports this style by +adapting the workings of the command @kbd{C-c C-t}@footnote{This is also +true for the @kbd{t} command in the timeline and agenda buffers.}. When +used several times in succession, it will still cycle through all names, +in order to first select the right type for a task. But when you return +to the item after some time and execute @kbd{C-c C-t} again, it will +switch from any name directly to DONE. Use prefix arguments or +completion to quickly select a specific name. You can also review the +items of a specific TODO type in a sparse tree by using a numeric prefix +to @kbd{C-c C-v}. For example, to see all things Lucy has to do, you +would use @kbd{C-3 C-c C-v}. To collect Lucy's items from all agenda +files into a single buffer, you would use the prefix arg as well when +creating the global todo list: @kbd{C-3 C-c t}. -@node Per file keywords, , TODO types, TODO extensions -@subsection Setting up TODO keywords for individual files +@node Multiple sets in one file, Fast access to TODO states, TODO types, TODO extensions +@subsection Multiple keyword sets in one file +@cindex todo keyword sets + +Sometimes you may want to use different sets of TODO keywords in +parallel. For example, you may want to have the basic +@code{TODO}/@code{DONE}, but also a workflow for bug fixing, and a +separate state indicating that an item has been canceled (so it is not +DONE, but also does not require action). Your setup would then look +like this: + +@lisp +(setq org-todo-keywords + '((sequence "TODO" "|" "DONE") + (sequence "REPORT" "BUG" "KNOWNCAUSE" "|" "FIXED") + (sequence "|" "CANCELED"))) +@end lisp + +The keywords should all be different, this helps Org-mode to keep track +of which subsequence should be used for a given entry. In this setup, +@kbd{C-c C-t} only operates within a subsequence, so it switches from +@code{DONE} to (nothing) to @code{TODO}, and from @code{FIXED} to +(nothing) to @code{REPORT}. Therefore you need a mechanism to initially +select the correct sequence. Besides the obvious ways like typing a +keyword or using completion, you may also apply the following commands: + +@table @kbd +@kindex C-S-@key{right} +@kindex C-S-@key{left} +@item C-S-@key{right} +@itemx C-S-@key{left} +These keys jump from one TODO subset to the next. In the above example, +@kbd{C-S-@key{right}} would jump from @code{TODO} or @code{DONE} to +@code{REPORT}, and any of the words in the second row to @code{CANCELED}. +@kindex S-@key{right} +@kindex S-@key{left} +@item S-@key{right} +@itemx S-@key{left} +@kbd{S-@key{}} and @kbd{S-@key{}} and walk through +@emph{all} keywords from all sets, so for example @kbd{S-@key{}} +would switch from @code{DONE} to @code{REPORT} in the example above. +@end table + +@node Fast access to TODO states, Per-file keywords, Multiple sets in one file, TODO extensions +@subsection Fast access to TODO states + +If you would like to quickly change an entry to an arbitrary TODO state +instead of cycling through the states, you can set up keys for +single-letter access to the states. This is done by adding the section +key after each keyword, in parenthesis. For example: + +@lisp +(setq org-todo-keywords + '((sequence "TODO(t)" "|" "DONE(d)") + (sequence "REPORT(r)" "BUG(b)" "KNOWNCAUSE(k)" "|" "FIXED(f)") + (sequence "|" "CANCELED(c)"))) +@end lisp + +If you then press @code{C-u C-c C-t} followed by the selection key, the +entry will be switched to this state. @key{SPC} can be used to remove +any TODO keyword from an entry. Should you like this way of selecting +TODO states a lot, you might want to set the variable +@code{org-use-fast-todo-selection} to @code{t} and make this behavior +the default. Check also the variable +@code{org-fast-tag-selection-include-todo}, it allows to change the TODO +state through the tags interface (@pxref{Setting tags}), in case you +like to mingle the two concepts. + +@node Per-file keywords, Faces for TODO keywords, Fast access to TODO states, TODO extensions +@subsection Setting up keywords for individual files @cindex keyword options -@cindex per file keywords +@cindex per-file keywords -It can be very useful to use different aspects of the TODO mechanism -in different files, which is not possible with the global settings -described above. For file-local settings, you need to add special -lines to the file which set the keywords and interpretation for that -file only. For example, to set one of the two examples discussed -above, you need one of the following lines, starting in column zero -anywhere in the file: +It can be very useful to use different aspects of the TODO mechanism in +different files. For file-local settings, you need to add special lines +to the file which set the keywords and interpretation for that file +only. For example, to set one of the two examples discussed above, you +need one of the following lines, starting in column zero anywhere in the +file: @example -#+SEQ_TODO: TODO FEEDBACK VERIFY DONE -#+TYP_TODO: Fred Sara Lucy Mike DONE +#+SEQ_TODO: TODO FEEDBACK VERIFY | DONE CANCELED +@end example +or +@example +#+TYP_TODO: Fred Sara Lucy Mike | DONE +@end example + +A setup for using several sets in parallel would be: + +@example +#+SEQ_TODO: TODO | DONE +#+SEQ_TODO: REPORT BUG KNOWNCAUSE | FIXED +#+SEQ_TODO: | CANCELED @end example @cindex completion, of option keywords @@ -2627,43 +2907,172 @@ anywhere in the file: @samp{#+} into the buffer and then use @kbd{M-@key{TAB}} completion. @cindex DONE, final TODO keyword -Remember that the last keyword must always mean that the item is DONE -(although you may use a different word). Also note that in each file, -only one of the two aspects of TODO keywords can be used. After -changing one of these lines, use @kbd{C-c C-c} with the cursor still -in the line to make the changes known to Org-mode@footnote{Org-mode -parses these lines only when Org-mode is activated after visiting a -file. @kbd{C-c C-c} with the cursor in a line starting with @samp{#+} -is simply restarting Org-mode for the current buffer.}. +Remember that the keywords after the vertical bar (or the last keyword +if no bar is there) must always mean that the item is DONE (although you +may use a different word). After changing one of these lines, use +@kbd{C-c C-c} with the cursor still in the line to make the changes +known to Org-mode@footnote{Org-mode parses these lines only when +Org-mode is activated after visiting a file. @kbd{C-c C-c} with the +cursor in a line starting with @samp{#+} is simply restarting Org-mode +for the current buffer.}. -If you want to use very many keywords, for example when working with a -large group of people, you may split the names over several lines: +@node Faces for TODO keywords, , Per-file keywords, TODO extensions +@subsection Faces for TODO keywords +@cindex faces, for TODO keywords +Org-mode highlights TODO keywords with special faces: @code{org-todo} +for keywords indicating that an item still has to be acted upon, and +@code{org-done} for keywords indicating that an item is finished. If +you are using more than 2 different states, you might want to use +special faces for some of them. This can be done using the variable +@code{org-todo-keyword-faces}. For example: + +@lisp +(setq org-todo-keyword-faces + '(("TODO" . org-warning) + ("DEFERRED" . shadow) + ("CANCELED" . (:foreground "blue" :weight bold)))) +@end lisp + +While using a list with face properties as shown for CANCELED +@emph{should} work, this does not aways seem to be the case. If +necessary, define a special face and use that. + +@page +@node Progress logging, Priorities, TODO extensions, TODO items +@section Progress Logging +@cindex progress logging +@cindex logging, of progress + +Org-mode can automatically record a time stamp and possibly a note when +you mark a TODO item as DONE, or even each time you change the state of +a TODO item. This system is highly configurable, settings can be on a +per-keyword basis and can be localized to a file or even a subtree. For +information on how to clock working time for a task, see @ref{Clocking +work time}. + +@menu +* Closing items:: When was this entry marked DONE? +* Tracking TODO state changes:: When did the status change? +@end menu + +@node Closing items, Tracking TODO state changes, Progress logging, Progress logging +@subsection Closing items + +The most basic logging is to keep track of @emph{when} a certain TODO +item was finished. This is achieved with@footnote{The corresponding +in-buffer setting is: @code{#+STARTUP: logdone}}. + +@lisp +(setq org-log-done 'time) +@end lisp + +@noindent +Then each time you turn an entry from a TODO (not-done) state into any +of the DONE states, a line @samp{CLOSED: [timestamp]} will be inserted +just after the headline. If you turn the entry back into a TODO item +through further state cycling, that line will be removed again. If you +want to record a note along with the timestamp, use@footnote{The +corresponding in-buffer setting is: @code{#+STARTUP: lognotedone}} + +@lisp +(setq org-log-done 'note) +@end lisp + +@noindent +You will then be prompted for a note, and that note will be stored below +the entry with a @samp{Closing Note} heading. + +In the timeline (@pxref{Timeline}) and in the agenda +(@pxref{Weekly/Daily agenda}), you can then use the @kbd{l} key to +display the TODO items with a @samp{CLOSED} timestamp on each day, +giving you an overview of what has been done. + +@node Tracking TODO state changes, , Closing items, Progress logging +@subsection Tracking TODO state changes + +When TODO keywords are used as workflow states (@pxref{Workflow +states}), you might want to keep track of when a state change occurred +and maybe take a note about this change. Since it is normally too much +to record a note for every state, Org-mode expects configuration on a +per-keyword basis for this. This is achieved by adding special markers +@samp{!} (for a time stamp) and @samp{@@} (for a note) in parenthesis +after each keyword. For example, with the setting + +@lisp +(setq org-todo-keywords + '((sequence "TODO(t)" "WAIT(w@@/!)" "|" "DONE(d!)" "CANCELED(c@@)"))) +@end lisp + +@noindent +you not only define global TODO keywords and fast access keys, but also +request that a time is recorded when the entry is turned into +DONE@footnote{It is possible that Org-mode will record two time stamps +when you are using both @code{org-log-done} and state change logging. +However, it will never prompt for two notes - if you have configured +both, the state change recording note will take precedence and cancel +the @samp{Closing Note}.}, and that a note is recorded when switching to +WAIT or CANCELED. The setting for WAIT is even more special: The +@samp{!} after the slash means that in addition to the note taken when +entering the state, a time stamp should be recorded when @i{leaving} the +WAIT state, if and only if the @i{target} state does not configure +logging for entering it. So it has no effect when switching from WAIT +to DONE, because DONE is configured to record a timestamp only. But +when switching from WAIT back to TODO, the @samp{/!} in the WAIT +setting now triggers a timestamp even though TODO has no logging +configured. + +You can use the exact same syntax for setting logging preferences local +to a buffer: @example -#+TYP_TODO: Fred Sara Lucy Mike -#+TYP_TODO: Luis George Jules Jessica -#+TYP_TODO: Kim Arnold Peter -#+TYP_TODO: DONE +#+SEQ_TODO: TODO(t) WAIT(w@@/!) | DONE(d!) CANCELED(c@@) @end example -@node Priorities, Breaking down tasks, TODO extensions, TODO items +In order to define logging settings that are local to a subtree or a +single item, define a LOGGING property in this entry. Any non-empty +LOGGING property resets all logging settings to nil. You may then turn +on logging for this specific tree using STARTUP keywords like +@code{lognotedone} or @code{logrepeat}, as well as adding state specific +settings like @code{TODO(!)}. For example + +@example +* TODO Log each state with only a time + :PROPERTIES: + :LOGGING: TODO(!) WAIT(!) DONE(!) CANCELED(!) + :END: +* TODO Only log when switching to WAIT, and when repeating + :PROPERTIES: + :LOGGING: WAIT(@@) logrepeat + :END: +* TODO No logging at all + :PROPERTIES: + :LOGGING: nil + :END: +@end example + + +@node Priorities, Breaking down tasks, Progress logging, TODO items @section Priorities @cindex priorities -If you use Org-mode extensively to organize your work, you may end up -with a number of TODO entries so large that you'd like to prioritize -them. This can be done by placing a @emph{priority cookie} into the -headline, like this +If you use Org-mode extensively, you may end up enough TODO items that +it starts to make sense to prioritize them. Prioritizing can be done by +placing a @emph{priority cookie} into the headline of a TODO item, like +this @example *** TODO [#A] Write letter to Sam Fortune @end example @noindent -With its standard setup, Org-mode supports priorities @samp{A}, -@samp{B}, and @samp{C}. @samp{A} is the highest priority. An entry -without a cookie is treated as priority @samp{B}. Priorities make a -difference only in the agenda (@pxref{Weekly/Daily agenda}). +By default, Org-mode supports three priorities: @samp{A}, @samp{B}, and +@samp{C}. @samp{A} is the highest priority. An entry without a cookie +is treated as priority @samp{B}. Priorities make a difference only in +the agenda (@pxref{Weekly/Daily agenda}); outside the agenda, they have +no inherent meaning to Org-mode. + +Priorities can be attached to any outline tree entries; they do not need +to be TODO items. @table @kbd @kindex @kbd{C-c ,} @@ -2673,21 +3082,33 @@ priority character @samp{A}, @samp{B} or @samp{C}. When you press @key{SPC} instead, the priority cookie is removed from the headline. The priorities can also be changed ``remotely'' from the timeline and agenda buffer with the @kbd{,} command (@pxref{Agenda commands}). - +@c @kindex S-@key{up} @kindex S-@key{down} @item S-@key{up} @itemx S-@key{down} -Increase/decrease priority of current headline. Note that these keys -are also used to modify time stamps (@pxref{Creating timestamps}). +Increase/decrease priority of current headline@footnote{See also the +option @code{org-priority-start-cycle-with-default'}.}. Note that these +keys are also used to modify time stamps (@pxref{Creating timestamps}). Furthermore, these keys are also used by CUA-mode (@pxref{Conflicts}). @end table +You can change the range of allowed priorities by setting the variables +@code{org-highest-priority}, @code{org-lowest-priority}, and +@code{org-default-priority}. For an individual buffer, you may set +these values (highest, lowest, default) like this (please make sure that +the highest priority is earlier in the alphabet than the lowest +priority): + +@example +#+PRIORITIES: A C B +@end example + @node Breaking down tasks, Checkboxes, Priorities, TODO items @section Breaking tasks down into subtasks @cindex tasks, breaking down -It is often advisable to break down large tasks into smaller, managable +It is often advisable to break down large tasks into smaller, manageable subtasks. You can do this by creating an outline tree below a TODO item, with detailed subtasks on the tree@footnote{To keep subtasks out of the global TODO list, see the @@ -2700,17 +3121,19 @@ of checkboxes to identify (a hierarchy of) a large number of subtasks @section Checkboxes @cindex checkboxes -Every item in a plain list (@pxref{Plain lists}) can be made a checkbox -by starting it with the string @samp{[ ]}. This feature is similar to -TODO items (@pxref{TODO items}), but more lightweight. Checkboxes are -not included into the global TODO list, so they are often great to split -a task into a number of simple steps. Or you can use them in a shopping -list. To toggle a checkbox, use @kbd{C-c C-c}, or try Piotr Zielinski's -@file{org-mouse.el}. Here is an example of a checkbox list. +Every item in a plain list (@pxref{Plain lists}) can be made into a +checkbox by starting it with the string @samp{[ ]}. This feature is +similar to TODO items (@pxref{TODO items}), but is more lightweight. +Checkboxes are not included into the global TODO list, so they are often +great to split a task into a number of simple steps. Or you can use +them in a shopping list. To toggle a checkbox, use @kbd{C-c C-c}, or +use the mouse (thanks to Piotr Zielinski's @file{org-mouse.el}). + +Here is an example of a checkbox list. @example -* TODO Organize party [3/6] - - call people [1/3] +* TODO Organize party [2/4] + - [-] call people [1/3] - [ ] Peter - [X] Sarah - [ ] Sam @@ -2719,26 +3142,33 @@ list. To toggle a checkbox, use @kbd{C-c C-c}, or try Piotr Zielinski's - [X] talk to the neighbors @end example +Checkboxes work hierarchically, so if a checkbox item has children that +are checkboxes, toggling one of the children checkboxes will make the +parent checkbox reflect if none, some, or all of the children are +checked. + @cindex statistics, for checkboxes @cindex checkbox statistics -The @samp{[3/6]} and @samp{[1/3]} in the first and second line are -cookies indicating how many checkboxes are present in this entry, and -how many of them have been checked off. This can give you an idea on -how many checkboxes remain, even without opening a folded entry. The -cookies can be placed into a headline or into (the first line of) a -plain list item. Each cookie covers all checkboxes structurally below -that headline/item. You have to insert the cookie yourself by typing -either @samp{[/]} or @samp{[%]}. In the first case you get an @samp{n -out of m} result, in the second case you get information about the +The @samp{[2/4]} and @samp{[1/3]} in the first and second line are +cookies indicating how many checkboxes present in this entry have been +checked off, and the total number of checkboxes are present. This can +give you an idea on how many checkboxes remain, even without opening a +folded entry. The cookies can be placed into a headline or into (the +first line of) a plain list item. Each cookie covers all checkboxes +structurally below the headline/item on which the cookie appear. You +have to insert the cookie yourself by typing either @samp{[/]} or +@samp{[%]}. With @samp{[/]} you get an @samp{n out of m} result, as in +the examples above. With @samp{[%]} you get information about the percentage of checkboxes checked (in the above example, this would be -@samp{[50%]} and @samp{[33%], respectively}). +@samp{[50%]} and @samp{[33%]}, respectively). @noindent The following commands work with checkboxes: @table @kbd @kindex C-c C-c @item C-c C-c -Toggle checkbox at point. +Toggle checkbox at point. With prefix argument, set it to @samp{[-]}, +which is considered to be an intermediate state. @kindex C-c C-x C-b @item C-c C-x C-b Toggle checkbox at point. @@ -2769,542 +3199,22 @@ delete boxes or add/change them by hand, use this command to get things back into synch. Or simply toggle any checkbox twice with @kbd{C-c C-c}. @end table -@node Timestamps, Tags, TODO items, Top -@chapter Timestamps -@cindex time stamps -@cindex date stamps - -Items can be labeled with timestamps to make them useful for project -planning. - -@menu -* Time stamps:: Assigning a time to a tree entry -* Creating timestamps:: Commands which insert timestamps -* Custom time format:: If you cannot work with the ISO format -* Repeating items:: Deadlines that come back again and again -* Progress logging:: Documenting when what work was done. -@end menu - - -@node Time stamps, Creating timestamps, Timestamps, Timestamps -@section Time stamps, deadlines and scheduling -@cindex time stamps -@cindex ranges, time -@cindex date stamps -@cindex deadlines -@cindex scheduling - -A time stamp is a specification of a date (possibly with time) in a -special format, either @samp{<2003-09-16 Tue>} or @samp{<2003-09-16 Tue -09:39>}@footnote{This is the standard ISO date/time format. If you -cannot get used to these, see @ref{Custom time format}}. A time stamp -can appear anywhere in the headline or body of an org-tree entry. Its -presence allows entries to be shown on specific dates in the agenda -(@pxref{Weekly/Daily agenda}). We distinguish: - -@table @var -@item Plain time stamp -@cindex timestamp -A simple time stamp just assigns a date/time to an item. This is just -like writing down an appointment in a paper agenda, or like writing down -an event in a diary, when you want to take note of when something -happened. In the timeline and agenda displays, the headline of an entry -associated with a plain time stamp will be shown exactly on that date. - -@example -* Meet Peter at the movies <2006-11-01 Wed 19:15> -@end example - -@item Inactive time stamp -@cindex timestamp, inactive -@cindex inactive timestamp -Just like a plain time stamp, but with square brackets instead of -angular ones. These time stamps are inactive in the sense that they do -@emph{not} trigger an entry to show up in the agenda. - -@example -* Gillian comes late for the fifth time [2006-11-01 Wed] -@end example - -@item Time stamp range -@cindex timerange -Two time stamps connected by @samp{--} denote a time range. The -headline will be shown on the first and last day of the range, and on -any dates that are displayed and fall in the range. Here is an -example: - -@example -** Meeting in Amsterdam - <2004-08-23 Mon>--<2004-08-26 Thu> -@end example - -@item Time stamp with SCHEDULED keyword -@cindex SCHEDULED keyword -If a time stamp is preceded by the word @samp{SCHEDULED:}, it means you -are planning to start working on that task on the given date. So this is -not about recording an event, but about planning your work. The -headline will be listed under the given date@footnote{It will still be -listed on that date after it has been marked DONE. If you don't like -this, set the variable @code{org-agenda-skip-scheduled-if-done}.}. In -addition, a reminder that the scheduled date has passed will be present -in the compilation for @emph{today}, until the entry is marked DONE. -I.e., the task will automatically be forwarded until completed. - -@example -*** TODO Call Trillian for a date on New Years Eve. - SCHEDULED: <2004-12-25 Sat> -@end example - -@item Time stamp with DEADLINE keyword -@cindex DEADLINE keyword -If a time stamp is preceded by the word @samp{DEADLINE:}, the task -(most likely a TODO item) is supposed to be finished on that date, and -it will be listed then. In addition, the compilation for @emph{today} -will carry a warning about the approaching or missed deadline, -starting @code{org-deadline-warning-days} before the due date, and -continuing until the entry is marked DONE. An example: - -@example -*** TODO write article about the Earth for the Guide - The editor in charge is [[bbdb:Ford Prefect]] - DEADLINE: <2004-02-29 Sun> -@end example -@item Time stamp with CLOSED keyword -@cindex CLOSED keyword -When @code{org-log-done} is non-nil, Org-mode will automatically insert -a special time stamp each time a TODO entry is marked done -(@pxref{Progress logging}). This time stamp is enclosed in square -brackets instead of angular brackets. - -@item Time range with CLOCK keyword -@cindex CLOCK keyword -When using the clock to time the work that is being done on specific -items, time ranges preceded by the CLOCK keyword are inserted -automatically into the file. The time stamps are enclosed in square -brackets instead of angular brackets. @xref{Clocking work time}. -@end table - -@node Creating timestamps, Custom time format, Time stamps, Timestamps -@section Creating timestamps -@cindex creating timestamps -@cindex timestamps, creating - -For Org-mode to recognize time stamps, they need to be in the specific -format. All commands listed below produce time stamps in the correct -format. - -@table @kbd -@kindex C-c . -@item C-c . -Prompt for a date and insert a corresponding time stamp. When the -cursor is at a previously used time stamp, it is updated to NOW. When -this command is used twice in succession, a time range is inserted. - -@kindex C-u C-c . -@item C-u C-c . -Like @kbd{C-c .}, but use the alternative format which contains date -and time. The default time can be rounded to multiples of 5 minutes, -see the option @code{org-time-stamp-rounding-minutes}. - -@kindex C-c ! -@item C-c ! -Like @kbd{C-c .}, but insert an inactive time stamp not triggering the -agenda. - -@kindex C-c < -@item C-c < -Insert a time stamp corresponding to the cursor date in the Calendar. - -@kindex C-c > -@item C-c > -Access the Emacs calendar for the current date. If there is a -timestamp in the current line, goto the corresponding date -instead. - -@kindex C-c C-o -@item C-c C-o -Access the agenda for the date given by the time stamp or -range at -point (@pxref{Weekly/Daily agenda}). - -@kindex C-c C-d -@item C-c C-d -Insert @samp{DEADLINE} keyword along with a stamp. The insertion will -happen in the line directly following the headline. -@c FIXME Any CLOSED timestamp will be removed.???????? - -@kindex C-c C-w -@cindex sparse tree, for deadlines -@item C-c C-w -Create a sparse tree with all deadlines that are either past-due, or -which will become due within @code{org-deadline-warning-days}. -With @kbd{C-u} prefix, show all deadlines in the file. With a numeric -prefix, check that many days. For example, @kbd{C-1 C-c C-w} shows -all deadlines due tomorrow. - -@kindex C-c C-s -@item C-c C-s -Insert @samp{SCHEDULED} keyword along with a stamp. The insertion will -happen in the line directly following the headline. Any CLOSED -timestamp will be removed. - -@kindex S-@key{left} -@kindex S-@key{right} -@item S-@key{left} -@itemx S-@key{right} -Change date at cursor by one day. These key bindings conflict with -CUA-mode (@pxref{Conflicts}). - -@kindex S-@key{up} -@kindex S-@key{down} -@item S-@key{up} -@itemx S-@key{down} -Change the item under the cursor in a timestamp. The cursor can be on a -year, month, day, hour or minute. Note that if the cursor is in a -headline and not at a time stamp, these same keys modify the priority of -an item. (@pxref{Priorities}). The key bindings also conflict with -CUA-mode (@pxref{Conflicts}). - - -@kindex C-c C-y -@cindex evaluate time range -@item C-c C-y -Evaluate a time range by computing the difference between start and -end. With prefix arg, insert result after the time range (in a table: -into the following column). -@end table - - -@menu -* The date/time prompt:: How org-mode helps you entering date and time -@end menu - -@node The date/time prompt, , Creating timestamps, Creating timestamps -@subsection The date/time prompt -@cindex date, reading in minibuffer -@cindex time, reading in minibuffer - -When Org-mode prompts for a date/time, the prompt suggests to enter an -ISO date. But it will in fact accept any string containing some date -and/or time information. You can, for example, use @kbd{C-y} to paste a -(possibly multi-line) string copied from an email message. Org-mode -will find whatever information is in there and will replace anything not -specified with the current date and time. For example: - -@example - 3-2-5 --> 2003-02-05 - feb 15 --> currentyear-02-15 - sep 12 9 --> 2009-09-12 - 12:45 --> today 12:45 - 22 sept 0:34 --> currentyear-09-22 0:34 - 12 --> currentyear-currentmonth-12 - Fri --> nearest Friday (today or later) - +4 --> 4 days from now (if +N is the only thing given) -@end example - -The function understands English month and weekday abbreviations. If -you want to use unabbreviated names and/or other languages, configure -the variables @code{parse-time-months} and @code{parse-time-weekdays}. - -@cindex calendar, for selecting date -Parallel to the minibuffer prompt, a calendar is popped up@footnote{If -you don't need/want the calendar, configure the variable -@code{org-popup-calendar-for-date-prompt}.}. When you exit the date -prompt, either by clicking on a date in the calendar, or by pressing -@key{RET}, the date selected in the calendar will be combined with the -information entered at the prompt. You can control the calendar fully -from the minibuffer: - -@table @kbd -@kindex < -@item < -Scroll calendar backwards by one month. -@kindex > -@item > -Scroll calendar forwards by one month. -@kindex mouse-1 -@item mouse-1 -Select date by clicking on it. -@kindex S-@key{right} -@item S-@key{right} -One day forward. -@kindex S-@key{left} -@item S-@key{left} -One day back. -@kindex S-@key{down} -@item S-@key{down} -One week forward. -@kindex S-@key{up} -@item S-@key{up} -One week back. -@kindex M-S-@key{right} -@item M-S-@key{right} -One month forward. -@kindex M-S-@key{left} -@item M-S-@key{left} -One month back. -@kindex @key{RET} -@item @key{RET} -Choose date in calendar (only if nothing was typed into minibuffer). -@end table - -@node Custom time format, Repeating items, Creating timestamps, Timestamps -@section Custom time format -@cindex custom date/time format -@cindex time format, custom -@cindex date format, custom - -Org-mode uses the standard ISO notation for dates and times as it is -defined in ISO 8601. If you cannot get used to this and require another -representation of date and time to keep you happy, you can get it by -customizing the variables @code{org-display-custom-times} and -@code{org-time-stamp-custom-formats}. - -@table @kbd -@kindex C-c C-x C-t -@item C-c C-x C-t -Toggle the display of custom formats for dates and times. -@end table - -@noindent -Org-mode needs the default format for scanning, so the custom date/time -format does not @emph{replace} the default format - instead it is put -@emph{over} the default format using text properties. This has the -following consequences: -@itemize @bullet -@item -You cannot place the cursor onto a time stamp anymore, only before or -after. -@item -The @kbd{S-@key{up}/@key{down}} keys can no longer be used to adjust -each component of a time stamp. If the cursor is at the beginning of -the stamp, @kbd{S-@key{up}/@key{down}} will change the stamp by one day, -just like @kbd{S-@key{left}/@key{right}}. At the end of the stamp, the -time will be changed by one minute. -@item -When you delete a time stamp character-by-character, it will only -disappear from the buffer after @emph{all} (invisible) characters -belonging to the ISO timestamp have been removed. -@item -If the custom time stamp format is longer than the default and you are -using dates in tables, table alignment will be messed up. If the custom -format is shorter, things do work as expected. -@end itemize - -@node Repeating items, Progress logging, Custom time format, Timestamps -@section Repeating items -@cindex TODO items, repeating -@cindex deadlines, repeating -@cindex scheduling, repeating - -Org-mode integrates with the Emacs calendar and diary to display cyclic -appointments, anniversaries and other special entries in the agenda -(@pxref{Weekly/Daily agenda}). However, it can be useful to have -certain deadlines and scheduling items to auto-repeat. The advantage of -a deadline or scheduled item is that the they produce warnings ahead of -time and automatically forward themselves in the agenda until they are -done. The abstract difference is therefore between cyclic -@i{appointments} and cyclic @i{action items}. For appointments you -should use the diary, for actions you can uses an org-mode deadline or -scheduling time stamp together with a REPEAT cookie. For example: - -@example -* TODO Replace batteries in smoke detector REPEAT(+18m) - SCHEDULED: <2007-01-01 Mon> - -* TODO Get dentist appointment REPEAT(+6m) - SCHEDULED: <2006-12-19 Tue> - -* TODO Tax report to IRS REPEAT(+1y) - DEADLINE: <2007-04-01 Sun> -@end example - -Each time you try to mark one of these entries DONE using @kbd{C-c C-t}, -they will automatically switch back to the state TODO, and the -deadline/scheduling will be shifted accordingly. The time units -recognized by org-mode are year (y), month (m), week (w), and day (d). -Org-mode will also prompt you for a note and record the fact that you -have closed this item in a note under the headline. - -One unusual property of these repeating items is that only one instance -of each exist at any given time. So if you look back or ahead in the -agenda, you will not find past and future instances, only the current -one will show up. Use a cyclic diary entry if you need all past and -future instances to be visible in the agenda. - -@node Progress logging, , Repeating items, Timestamps -@section Progress Logging -@cindex progress logging -@cindex logging, of progress - -Org-mode can automatically record a time stamp when you mark a TODO item -as DONE, or even each time when you change the state of a TODO item. -You can also measure precisely the time you spent on specific items in a -project by starting and stopping a clock when you start and stop working -on an aspect of a project. - -@menu -* Closing items:: When was this entry marked DONE? -* Tracking TODO state changes:: When did the status change? -* Clocking work time:: When exactly did you work on this item? -@end menu - -@node Closing items, Tracking TODO state changes, Progress logging, Progress logging -@subsection Closing items - -If you want to keep track of @emph{when} a certain TODO item was -finished, turn on logging with@footnote{The corresponding in-buffer -setting is: @code{#+STARTUP: logdone}} - -@lisp -(setq org-log-done t) -@end lisp - -@noindent -Then each time you turn a TODO entry into DONE using either @kbd{C-c -C-t} in the Org-mode buffer or @kbd{t} in the agenda buffer, a line -@samp{CLOSED: [timestamp]} will be inserted just after the headline. If -you turn the entry back into a TODO item through further state cycling, -that line will be removed again. In the timeline (@pxref{Timeline}) and -in the agenda (@pxref{Weekly/Daily agenda}), you can then use the -@kbd{l} key to display the TODO items closed on each day, giving you an -overview of what has been done on a day. If you want to record a note -along with the timestamp, use@footnote{The corresponding in-buffer -setting is: @code{#+STARTUP: lognotedone}} - -@lisp -(setq org-log-done '(done)) -@end lisp - -@node Tracking TODO state changes, Clocking work time, Closing items, Progress logging -@subsection Tracking TODO state changes - -When TODO keywords are used as workflow states (@pxref{Workflow -states}), you might want to keep track of when a state change occurred, -and you may even want to attach notes to that state change. With the -setting - -@lisp -(setq org-log-done '(state)) -@end lisp - -@noindent -each state change will prompt you for a note that will be attached to -the current headline. Very likely you do not want this verbose tracking -all the time, so it is probably better to configure this behavior with -in-buffer options. For example, if you are tracking purchases, put -these into a separate file that starts with: - -@example -#+SEQ_TODO: TODO ORDERED INVOICE PAYED RECEIVED SENT -#+STARTUP: lognotestate -@end example - -@node Clocking work time, , Tracking TODO state changes, Progress logging -@subsection Clocking work time - -Org-mode allows you to clock the time you spent on specific tasks in a -project. When you start working on an item, you can start the clock. -When you stop working on that task, or when you mark the task done, the -clock is stopped and the corresponding time interval is recorded. It -also computes the total time spent on each subtree of a project. - -@table @kbd -@kindex C-c C-x C-i -@item C-c C-x C-i -Start the clock on the current item (clock-in). This inserts the CLOCK -keyword together with a timestamp. -@kindex C-c C-x C-o -@item C-c C-x C-o -Stop the clock (clock-out). The inserts another timestamp at the same -location where the clock was last started. It also directly computes -the resulting time in inserts it after the time range as @samp{=> -HH:MM}. See the variable @code{org-log-done} for the possibility to -record an additional note together with the clock-out time -stamp@footnote{The corresponding in-buffer setting is: @code{#+STARTUP: -lognoteclock-out}}. -@kindex C-c C-y -@item C-c C-y -Recompute the time interval after changing one of the time stamps. This -is only necessary if you edit the time stamps directly. If you change -them with @kbd{S-@key{cursor}} keys, the update is automatic. -@kindex C-c C-t -@item C-c C-t -Changing the TODO state of an item to DONE automatically stops the clock -if it is running in this same item. -@kindex C-c C-x C-x -@item C-c C-x C-x -Cancel the current clock. This is useful if a clock was started by -mistake, or if you ended up working on something else. -@kindex C-c C-x C-d -@item C-c C-x C-d -Display time summaries for each subtree in the current buffer. This -puts overlays at the end of each headline, showing the total time -recorded under that heading, including the time of any subheadings. You -can use visibility cycling to study the tree, but the overlays disappear -when you change the buffer (see variable -@code{org-remove-highlights-with-change}) or press @kbd{C-c C-c}. -@kindex C-c C-x C-r -@item C-c C-x C-r -Insert a dynamic block (@pxref{Dynamic blocks}) containing a clock -report as an org-mode table into the current file. -@example -#+BEGIN: clocktable :maxlevel 2 :emphasize nil - -#+END: clocktable -@end example -@noindent -If such a block already exists, its content is replaced by the new -table. The @samp{BEGIN} line can specify options: -@example -:maxlevels @r{Maximum level depth to which times are listed in the table.} -:emphasize @r{When @code{t}, emphasize level one and level two items} -:block @r{The time block to consider. This block is specified relative} - @r{to the current time and may be any of these keywords:} - @r{@code{today}, @code{yesterday}, @code{thisweek}, @code{lastweek},} - @r{@code{thismonth}, @code{lastmonth}, @code{thisyear}, or @code{lastyear}}. -:tstart @r{A time string specifying when to start considering times} -:tend @r{A time string specifying when to stop considering times} -@end example -So to get a clock summary for the current day, you could write -@example -#+BEGIN: clocktable :maxlevel 2 :block today - -#+END: clocktable -@end example -and to use a specific time range you could write@footnote{Note that all -parameters must be specified in a single line - the line is broken here -only to fit it onto the manual.} -@example -#+BEGIN: clocktable :tstart "<2006-08-10 Thu 10:00>" - :tend "<2006-08-10 Thu 12:00>" - -#+END: clocktable -@end example -@kindex C-u C-c C-x C-u -@item C-u C-c C-x C-u -Update all dynamic blocks (@pxref{Dynamic blocks}). This is useful if -you have several clocktable blocks in a buffer. -@end table - -The @kbd{l} key may be used in the timeline (@pxref{Timeline}) and in -the agenda (@pxref{Weekly/Daily agenda}) to show which tasks have been -worked on or closed during a day. - -@node Tags, Agenda views, Timestamps, Top +@node Tags, Properties and columns, TODO items, Top @chapter Tags @cindex tags @cindex headline tagging @cindex matching, tags @cindex sparse tree, tag based -If you wish to implement a system of labels and contexts for -cross-correlating information, an excellent way is to assign @i{tags} to -headlines. Org-mode has extensive support for using tags. +An excellent way to implement labels and contexts for cross-correlating +information is to assign @i{tags} to headlines. Org-mode has extensive +support for tags. -Every headline can contain a list of tags, at the end of the headline. -Tags are normal words containing letters, numbers, @samp{_}, and -@samp{@@}. Tags must be preceded and followed by a single colon; like -@samp{:WORK:}. Several tags can be specified like @samp{:WORK:URGENT:}. +Every headline can contain a list of tags; they occur at the end of the +headline. Tags are normal words containing letters, numbers, @samp{_}, +and @samp{@@}. Tags must be preceded and followed by a single colon, +e.g., @samp{:WORK:}. Several tags can be specified, as in +@samp{:work:URGENT:}. @menu * Tag inheritance:: Tags use the tree structure of the outline @@ -3314,6 +3224,7 @@ Tags are normal words containing letters, numbers, @samp{_}, and @node Tag inheritance, Setting tags, Tags, Tags @section Tag inheritance +@cindex tag inheritance @cindex inheritance, of tags @cindex sublevels, inclusion into tags match @@ -3322,20 +3233,21 @@ heading has a certain tag, all subheadings will inherit the tag as well. For example, in the list @example -* Meeting with the French group :WORK: -** Summary by Frank :BOSS:NOTES: -*** TODO Prepare slides for him :ACTION: +* Meeting with the French group :work: +** Summary by Frank :boss:notes: +*** TODO Prepare slides for him :action: @end example @noindent -the final heading will have the tags @samp{:WORK:}, @samp{:BOSS:}, -@samp{:NOTES:}, and @samp{:ACTION:}. When executing tag searches and +the final heading will have the tags @samp{:work:}, @samp{:boss:}, +@samp{:notes:}, and @samp{:action:} even though the final heading is not +explicitly marked with those tags. When executing tag searches and Org-mode finds that a certain headline matches the search criterion, it -will not check any sublevel headline, assuming that these likely also -match, and that the list of matches can become very long. This may -not be what you want, however, and you can influence inheritance and -searching using the variables @code{org-use-tag-inheritance} and -@code{org-tags-match-list-sublevels}. +will not check any sublevel headline, assuming that these also match and +that the list of matches could become very long because of that. If you +do want the subevels be tested and listed as well, you may set the +variable @code{org-tags-match-list-sublevels}. To turn off tag +inheritance entirely, use the variable @code{org-use-tag-inheritance}. @node Setting tags, Tag searches, Tag inheritance, Tags @section Setting tags @@ -3367,13 +3279,13 @@ of tags with the variable @code{org-tag-alist}. Finally you can set the default tags for a given file with lines like @example -#+TAGS: @@WORK @@HOME @@TENNISCLUB -#+TAGS: Laptop Car PC Sailboat +#+TAGS: @@work @@home @@tennisclub +#+TAGS: laptop car pc sailboat @end example If you have globally defined your preferred set of tags using the variable @code{org-tag-alist}, but would like to use a dynamic tag list -in a specific file: Just add an empty TAGS option line to that file: +in a specific file, add an empty TAGS option line to that file: @example #+TAGS: @@ -3386,13 +3298,13 @@ single key per tag. To function efficiently, you should assign unique keys to most tags. This can be done globally with @lisp -(setq org-tag-alist '(("@@WORK" . ?w) ("@@HOME" . ?h) ("Laptop" . ?l))) +(setq org-tag-alist '(("@@work" . ?w) ("@@home" . ?h) ("laptop" . ?l))) @end lisp @noindent or on a per-file basis with @example -#+TAGS: @@WORK(w) @@HOME(h) @@TENNISCLUB(t) Laptop(l) PC(p) +#+TAGS: @@work(w) @@home(h) @@tennisclub(t) laptop(l) pc(p) @end example @noindent @@ -3402,11 +3314,11 @@ curly braces@footnote{In @code{org-mode-alist} use groups are allowed.} @example -#+TAGS: @{ @@WORK(w) @@HOME(h) @@TENNISCLUB(t) @} Laptop(l) PC(p) +#+TAGS: @{ @@work(w) @@home(h) @@tennisclub(t) @} laptop(l) pc(p) @end example -@noindent you indicate that at most one of @samp{@@WORK}, @samp{@@HOME}, -and @samp{@@TENNISCLUB} should be selected. +@noindent you indicate that at most one of @samp{@@work}, @samp{@@home}, +and @samp{@@tennisclub} should be selected. @noindent Don't forget to press @kbd{C-c C-c} with the cursor in one of these lines to activate any changes. @@ -3448,10 +3360,10 @@ selection window. @noindent This method lets you assign tags to a headline with very few keys. With -the above setup, you could clear the current tags and set @samp{@@HOME}, -@samp{Laptop} and @samp{PC} tags with just the following keys: @kbd{C-c -C-c @key{SPC} h l p @key{RET}}. Switching from @samp{@@HOME} to -@samp{@@WORK} would be done with @kbd{C-c C-c w @key{RET}} or +the above setup, you could clear the current tags and set @samp{@@home}, +@samp{laptop} and @samp{pc} tags with just the following keys: @kbd{C-c +C-c @key{SPC} h l p @key{RET}}. Switching from @samp{@@home} to +@samp{@@work} would be done with @kbd{C-c C-c w @key{RET}} or alternatively with @kbd{C-c C-c C-c w}. Adding the non-predefined tag @samp{Sarah} could be done with @kbd{C-c C-c @key{TAB} S a r a h @key{RET} @key{RET}}. @@ -3472,18 +3384,20 @@ when you press an extra @kbd{C-c}. @cindex tag searches @cindex searching for tags -Once a tags system has been set up, it can be used to collect related +Once a system of tags has been set up, it can be used to collect related information into special lists. @table @kbd @kindex C-c \ +@kindex C-c / T @item C-c \ +@itemx C-c / T Create a sparse tree with all headlines matching a tags search. With a @kbd{C-u} prefix argument, ignore headlines that are not a TODO line. @kindex C-c a m @item C-c a m Create a global list of tag matches from all agenda files. -@xref{Matching headline tags}. +@xref{Matching tags and properties}. @kindex C-c a M @item C-c a M Create a global list of tag matches from all agenda files, but check @@ -3500,14 +3414,14 @@ positive selection. The AND operator @samp{&} is optional when @samp{+} or @samp{-} is present. Examples: @table @samp -@item +WORK-BOSS -Select headlines tagged @samp{:WORK:}, but discard those also tagged -@samp{:BOSS:}. -@item WORK|LAPTOP -Selects lines tagged @samp{:WORK:} or @samp{:LAPTOP:}. -@item WORK|LAPTOP&NIGHT -Like before, but require the @samp{:LAPTOP:} lines to be tagged also -@samp{NIGHT}. +@item +work-boss +Select headlines tagged @samp{:work:}, but discard those also tagged +@samp{:boss:}. +@item work|laptop +Selects lines tagged @samp{:work:} or @samp{:laptop:}. +@item work|laptop&night +Like before, but require the @samp{:laptop:} lines to be tagged also +@samp{:night:}. @end table @cindex TODO keyword matching, with tags search @@ -3523,41 +3437,1364 @@ M}, or equivalently start the todo part after the slash with @samp{!}. Examples: @table @samp -@item WORK/WAITING -Select @samp{:WORK:}-tagged TODO lines with the specific TODO +@item work/WAITING +Select @samp{:work:}-tagged TODO lines with the specific TODO keyword @samp{WAITING}. -@item WORK/!-WAITING-NEXT -Select @samp{:WORK:}-tagged TODO lines that are neither @samp{WAITING} +@item work/!-WAITING-NEXT +Select @samp{:work:}-tagged TODO lines that are neither @samp{WAITING} nor @samp{NEXT} -@item WORK/+WAITING|+NEXT -Select @samp{:WORK:}-tagged TODO lines that are either @samp{WAITING} or +@item work/+WAITING|+NEXT +Select @samp{:work:}-tagged TODO lines that are either @samp{WAITING} or @samp{NEXT}. @end table @cindex regular expressions, with tags search Any element of the tag/todo match can be a regular expression - in this case it must be enclosed in curly braces. For example, -@samp{WORK+@{^BOSS.*@}} matches headlines that contain the tag -@samp{WORK} and any tag @i{starting} with @samp{BOSS}. +@samp{work+@{^boss.*@}} matches headlines that contain the tag +@samp{:work:} and any tag @i{starting} with @samp{boss}. -@cindex level, require for tags match -You can also require a headline to be of a certain level, by writing -instead of any TAG an expression like @samp{LEVEL=3}. For example, a -search @samp{+LEVEL=3+BOSS/-DONE} lists all level three headlines that -have the tag BOSS and are @emph{not} marked with the todo keyword DONE. +@cindex level, require for tags/property match +@cindex category, require for tags/property match +You can also require a headline to be of a certain level or category, by +writing instead of any TAG an expression like @samp{LEVEL=3} or +@samp{CATEGORY="work"}, respectively. For example, a search +@samp{+LEVEL=3+boss/-DONE} lists all level three headlines that have the +tag @samp{boss} and are @emph{not} marked with the todo keyword DONE. -@node Agenda views, Embedded LaTeX, Tags, Top +@node Properties and columns, Dates and times, Tags, Top +@chapter Properties and Columns +@cindex properties + +Properties are a set of key-value pairs associated with an entry. There +are two main applications for properties in Org-mode. First, properties +are like tags, but with a value. Second, you can use properties to +implement (very basic) database capabilities in an Org-mode buffer. For +an example of the first application, imagine maintaining a file where +you document bugs and plan releases of a piece of software. Instead of +using tags like @code{:release_1:}, @code{:release_2:}, one can use a +property, say @code{:Release:}, that in different subtrees has different +values, such as @code{1.0} or @code{2.0}. For an example of the second +application of properties, imagine keeping track of one's music CD's, +where properties could be things such as the album artist, date of +release, number of tracks, and so on. + +Properties can be conveniently edited and viewed in column view +(@pxref{Column view}). + +Properties are like tags, but with a value. For example, in a file +where you document bugs and plan releases of a piece of software, +instead of using tags like @code{:release_1:}, @code{:release_2:}, it +can be more efficient to use a property @code{:Release:} with a value +@code{1.0} or @code{2.0}. Second, you can use properties to implement +(very basic) database capabilities in an Org-mode buffer, for example to +create a list of Music CD's you own. You can edit and view properties +conveniently in column view (@pxref{Column view}). + +@menu +* Property syntax:: How properties are spelled out +* Special properties:: Access to other Org-mode features +* Property searches:: Matching property values +* Property inheritance:: Passing values down the tree +* Column view:: Tabular viewing and editing +* Property API:: Properties for Lisp programmers +@end menu + +@node Property syntax, Special properties, Properties and columns, Properties and columns +@section Property Syntax +@cindex property syntax +@cindex drawer, for properties + +Properties are key-value pairs. They need to be inserted into a special +drawer (@pxref{Drawers}) with the name @code{PROPERTIES}. Each property +is specified on a single line, with the key (surrounded by colons) +first, and the value after it. Here is an example: + +@example +* CD collection +** Classic +*** Goldberg Variations + :PROPERTIES: + :Title: Goldberg Variations + :Composer: J.S. Bach + :Artist: Glen Gould + :Publisher: Deutsche Grammphon + :NDisks: 1 + :END: +@end example + +You may define the allowed values for a particular property @samp{:Xyz:} +by setting a property @samp{:Xyz_ALL:}. This special property is +@emph{inherited}, so if you set it in a level 1 entry, it will apply to +the entire tree. When allowed values are defined, setting the +corresponding property becomes easier and is less prone to typing +errors. For the example with the CD collection, we can predefine +publishers and the number of disks in a box like this: + +@example +* CD collection + :PROPERTIES: + :NDisks_ALL: 1 2 3 4 + :Publisher_ALL: "Deutsche Grammophon" Phillips EMI + :END: +@end example + +If you want to set properties that can be inherited by any entry in a +file, use a line like + +@example +#+PROPERTY: NDisks_ALL 1 2 3 4 +@end example + +Property values set with the global variable +@code{org-global-properties} can be inherited by all entries in all +Org-mode files. + +@noindent +The following commands help to work with properties: + +@table @kbd +@kindex M-@key{TAB} +@item M-@key{TAB} +After an initial colon in a line, complete property keys. All keys used +in the current file will be offered as possible completions. +@kindex C-c C-x p +@item C-c C-x p +Set a property. This prompts for a property name and a value. If +necessary, the property drawer is created as well. +@item M-x org-insert-property-drawer +Insert a property drawer into the current entry. The drawer will be +inserted early in the entry, but after the lines with planning +information like deadlines. +@kindex C-c C-c +@item C-c C-c +With the cursor in a property drawer, this executes property commands. +@item C-c C-c s +Set a property in the current entry. Both the property and the value +can be inserted using completion. +@kindex S-@key{right} +@kindex S-@key{left} +@item S-@key{left}/@key{right} +Switch property at point to the next/previous allowed value. +@item C-c C-c d +Remove a property from the current entry. +@item C-c C-c D +Globally remove a property, from all entries in the current file. +@item C-c C-c c +Compute the property at point, using the operator and scope from the +nearest column format definition. +@end table + +@node Special properties, Property searches, Property syntax, Properties and columns +@section Special Properties +@cindex properties, special + +Special properties provide alternative access method to Org-mode +features discussed in the previous chapters, like the TODO state or the +priority of an entry. This interface exists so that you can include +these states into columns view (@pxref{Column view}), or to use them in +queries. The following property names are special and should not be +used as keys in the properties drawer: + +@example +TODO @r{The TODO keyword of the entry.} +TAGS @r{The tags defined directly in the headline.} +ALLTAGS @r{All tags, including inherited ones.} +PRIORITY @r{The priority of the entry, a string with a single letter.} +DEADLINE @r{The deadline time string, without the angular brackets.} +SCHEDULED @r{The scheduling time stamp, without the angular brackets.} +TIMESTAMP @r{The first keyword-less time stamp in the entry.} +TIMESTAMP_IA @r{The first inactive time stamp in the entry.} +CLOCKSUM @r{The sum of CLOCK intervals in the subtree. @code{org-clock-sum}} + @r{must be run first to compute the values.} +@end example + +@node Property searches, Property inheritance, Special properties, Properties and columns +@section Property searches +@cindex properties, searching +@cindex properties, inheritance +@cindex searching, of properties +@cindex inheritance, of properties + +To create sparse trees and special lists with selection based on +properties, the same commands are used as for tag searches (@pxref{Tag +searches}), and the same logic applies. For example, a search string + +@example ++work-boss+PRIORITY="A"+Coffee="unlimited"+Effort=""+With=@{Sarah\|Denny@} +@end example + +@noindent +finds entries tagged @samp{:work:} but not @samp{:boss:}, which +also have a priority value @samp{A}, a @samp{:Coffee:} property with the +value @samp{unlimited}, an @samp{Effort} property that is undefined or +empty, and a @samp{:With:} property that is matched by +the regular expression @samp{Sarah\|Denny}. + +You can configure Org-mode to use property inheritance during a search, +see @ref{Property inheritance} for details. + +There is also a special command for creating sparse trees based on a +single property: + +@table @kbd +@kindex C-c / p +@item C-c / p +Create a sparse tree based on the value of a property. This first +prompts for the name of a property, and then for a value. A sparse tree +is created with all entries that define this property with the given +value. If you enclose the value into curly braces, it is interpreted as +a regular expression and matched against the property values. +@end table + +@node Property inheritance, Column view, Property searches, Properties and columns +@section Property Inheritance + +The outline structure of Org-mode documents lends itself for an +inheritance model of properties: If the parent in a tree has a certain +property, the children can inherit this property. Org-mode does not +turn this on by default, because it can slow down property searches +significantly and is often not needed. However, if you find inheritance +useful, you can turn it on by setting the variable +@code{org-use-property-inheritance}. It may be set to @code{t}, to make +all properties inherited from the parent, or to a list of properties +that should be inherited. + +Org-mode has a few properties for which inheritance is hard-coded, at +least for the special applications for which they are used: + +@table @code +@item COLUMNS +The @code{:COLUMNS:} property defines the format of column view +(@pxref{Column view}). It is inherited in the sense that the level +where a @code{:COLUMNS:} property is defined is used as the starting +point for a column view table, independently of the location in the +subtree from where columns view is turned on. +@item CATEGORY +For agenda view, a category set through a @code{:CATEGORY:} property +applies to the entire subtree. +@item ARCHIVE +For archiving, the @code{:ARCHIVE:} property may define the archive +location for the entire subtree (@pxref{Moving subtrees}). +@item LOGGING +The LOGGING property may define logging settings for an entry or a +subtree (@pxref{Tracking TODO state changes}). +@end table + +@node Column view, Property API, Property inheritance, Properties and columns +@section Column View + +A great way to view and edit properties in an outline tree is +@emph{column view}. In column view, each outline item is turned into a +table row. Columns in this table provide access to properties of the +entries. Org-mode implements columns by overlaying a tabular structure +over the headline of each item. While the headlines have been turned +into a table row, you can still change the visibility of the outline +tree. For example, you get a compact table by switching to CONTENTS +view (@kbd{S-@key{TAB} S-@key{TAB}}, or simply @kbd{c} while column view +is active), but you can still open, read, and edit the entry below each +headline. Or, you can switch to column view after executing a sparse +tree command and in this way get a table only for the selected items. +Column view also works in agenda buffers (@pxref{Agenda views}) where +queries have collected selected items, possibly from a number of files. + +@menu +* Defining columns:: The COLUMNS format property +* Using column view:: How to create and use column view +* Capturing Column View:: A dynamic block for column view +@end menu + +@node Defining columns, Using column view, Column view, Column view +@subsection Defining Columns +@cindex column view, for properties +@cindex properties, column view + +Setting up a column view first requires defining the columns. This is +done by defining a column format line. + +@menu +* Scope of column definitions:: Where defined, where valid? +* Column attributes:: Appearance and content of a column +@end menu + +@node Scope of column definitions, Column attributes, Defining columns, Defining columns +@subsubsection Scope of column definitions + +To define a column format for an entire file, use a line like + +@example +#+COLUMNS: %25ITEM %TAGS %PRIORITY %TODO +@end example + +To specify a format that only applies to a specific tree, add a +@code{:COLUMNS:} property to the top node of that tree, for example: + +@example +** Top node for columns view + :PROPERTIES: + :COLUMNS: %25ITEM %TAGS %PRIORITY %TODO + :END: +@end example + +If a @code{:COLUMNS:} property is present in an entry, it defines columns +for the entry itself, and for the entire subtree below it. Since the +column definition is part of the hierarchical structure of the document, +you can define columns on level 1 that are general enough for all +sublevels, and more specific columns further down, when you edit a +deeper part of the tree. + +@node Column attributes, , Scope of column definitions, Defining columns +@subsubsection Column attributes +A column definition sets the attributes of a column. The general +definition looks like this: + +@example + %[width]property[(title)][@{summary-type@}] +@end example + +@noindent +Except for the percent sign and the property name, all items are +optional. The individual parts have the following meaning: + +@example +width @r{An integer specifying the width of the column in characters.} + @r{If omitted, the width will be determined automatically.} +property @r{The property that should be edited in this column.} +(title) @r{The header text for the column. If omitted, the} + @r{property name is used.} +@{summary-type@} @r{The summary type. If specified, the column values for} + @r{parent nodes are computed from the children.} + @r{Supported summary types are:} + @{+@} @r{Sum numbers in this column.} + @{+;%.1f@} @r{Like @samp{+}, but format result with @samp{%.1f}.} + @{$@} @r{Currency, short for @samp{+;%.2f}.} + @{:@} @r{Sum times, HH:MM:SS, plain numbers are hours.} + @{X@} @r{Checkbox status, [X] if all children are [X].} + @{X/@} @r{Checkbox status, [n/m].} + @{X%@} @r{Checkbox status, [n%].} +@end example + +@noindent +Here is an example for a complete columns definition, along with allowed +values. + +@example +:COLUMNS: %20ITEM %9Approved(Approved?)@{X@} %Owner %11Status \@footnote{Please note that the COLUMNS definition must be on a single line - it is wrapped here only because of formatting constraints.} + %10Time_Estimate@{:@} %CLOCKSUM +:Owner_ALL: Tammy Mark Karl Lisa Don +:Status_ALL: "In progress" "Not started yet" "Finished" "" +:Approved_ALL: "[ ]" "[X]" +@end example + +The first column, @samp{%25ITEM}, means the first 25 characters of the +item itself, i.e. of the headline. You probably always should start the +column definition with the @samp{ITEM} specifier. The other specifiers +create columns @samp{Owner} with a list of names as allowed values, for +@samp{Status} with four different possible values, and for a checkbox +field @samp{Approved}. When no width is given after the @samp{%} +character, the column will be exactly as wide as it needs to be in order +to fully display all values. The @samp{Approved} column does have a +modified title (@samp{Approved?}, with a question mark). Summaries will +be created for the @samp{Time_Estimate} column by adding time duration +expressions like HH:MM, and for the @samp{Approved} column, by providing +an @samp{[X]} status if all children have been checked. The +@samp{CLOCKSUM} column is special, it lists the sum of CLOCK intervals +in the subtree. + +@node Using column view, Capturing Column View, Defining columns, Column view +@subsection Using Column View + +@table @kbd +@tsubheading{Turning column view on and off} +@kindex C-c C-x C-c +@item C-c C-x C-c +Create the column view for the local environment. This command searches +the hierarchy, up from point, for a @code{:COLUMNS:} property that defines +a format. When one is found, the column view table is established for +the entire tree, starting from the entry that contains the @code{:COLUMNS:} +property. If none is found, the format is taken from the @code{#+COLUMNS} +line or from the variable @code{org-columns-default-format}, and column +view is established for the current entry and its subtree. +@kindex r +@item r +Recreate the column view, to included hanges happening in the buffer. +@kindex g +@item g +Same as @kbd{r}. +@kindex q +@item q +Exit column view. +@tsubheading{Editing values} +@item @key{left} @key{right} @key{up} @key{down} +Move through the column view from field to field. +@kindex S-@key{left} +@kindex S-@key{right} +@item S-@key{left}/@key{right} +Switch to the next/previous allowed value of the field. For this, you +have to have specified allowed values for a property. +@kindex n +@kindex p +@itemx n / p +Same as @kbd{S-@key{left}/@key{right}} +@kindex e +@item e +Edit the property at point. For the special properties, this will +invoke the same interface that you normally use to change that +property. For example, when editing a TAGS property, the tag completion +or fast selection interface will pop up. +@kindex C-c C-c +@item C-c C-c +When there is a checkbox at point, toggle it. +@kindex v +@item v +View the full value of this property. This is useful if the width of +the column is smaller than that of the value. +@kindex a +@item a +Edit the list of allowed values for this property. If the list is found +in the hierarchy, the modified values is stored there. If no list is +found, the new value is stored in the first entry that is part of the +current column view. +@tsubheading{Modifying the table structure} +@kindex < +@kindex > +@item < / > +Make the column narrower/wider by one character. +@kindex S-M-@key{right} +@item S-M-@key{right} +Insert a new column, to the right of the current column. +@kindex S-M-@key{left} +@item S-M-@key{left} +Delete the current column. +@end table + +@node Capturing Column View, , Using column view, Column view +@subsection Capturing Column View + +Since column view is just an overlay over a buffer, it cannot be +exported or printed directly. If you want to capture a column view, use +ths @code{columnview} dynamic block (@pxref{Dynamic blocks}). The frame +of this block looks like this: + +@example +* The column view +#+BEGIN: columnview :hlines 1 :id "label" + +#+END: +@end example + +@noindent This dynamic block has the following parameters: + +@table @code +@item :id +This is most important parameter. Column view is a feature that is +often localized to a certain (sub)tree, and the capture block might be +in a different location in the file. To identify the tree whose view to +capture, you can use 3 values: +@example +local @r{use the tree in which the capture block is located} +global @r{make a global view, including all headings in the file} +"label" @r{call column view in the tree that has and @code{:ID:}} + @r{property with the value @i{label}} +@end example +@item :hlines +When @code{t}, insert a hline after every line. When a number N, insert +a hline before each headline with level @code{<= N}. +@item :vlines +When set to @code{t}, enforce column groups to get vertical lines. +@item :maxlevel +When set to a number, don't capture entries below this level. +@item :skip-empty-rows +When set to @code{t}, skip row where the only non-empty specifier of the +column view is @code{ITEM}. + +@end table + +@noindent +The following commands insert or update the dynamic block: + +@table @kbd +@kindex C-c C-x r +@item C-c C-x r +Insert a dynamic block capturing a column view. You will be prompted +for the scope or id of the view. +@kindex C-c C-c +@item C-c C-c +@kindex C-c C-x C-u +@itemx C-c C-x C-u +Update dynamical block at point. The cursor needs to be in the +@code{#+BEGIN} line of the dynamic block. +@kindex C-u C-c C-x C-u +@item C-u C-c C-x C-u +Update all dynamic blocks (@pxref{Dynamic blocks}). This is useful if +you have several clocktable blocks in a buffer. +@end table + +@node Property API, , Column view, Properties and columns +@section The Property API +@cindex properties, API +@cindex API, for properties + +There is a full API for accessing and changing properties. This API can +be used by Emacs Lisp programs to work with properties and to implement +features based on them. For more information see @ref{Using the +property API}. + +@node Dates and times, Remember, Properties and columns, Top +@chapter Dates and Times +@cindex dates +@cindex times +@cindex time stamps +@cindex date stamps + +To assist project planning, TODO items can be labeled with a date and/or +a time. The specially formatted string carrying the date and time +information is called a @emph{timestamp} in Org-mode. This may be a +little confusing because timestamp is often used as indicating when +something was created or last changed. However, in Org-mode this term +is used in a much wider sense. + +@menu +* Time stamps:: Assigning a time to a tree entry +* Creating timestamps:: Commands which insert timestamps +* Deadlines and scheduling:: Planning your work +* Clocking work time:: +@end menu + + +@node Time stamps, Creating timestamps, Dates and times, Dates and times +@section Time stamps, deadlines and scheduling +@cindex time stamps +@cindex ranges, time +@cindex date stamps +@cindex deadlines +@cindex scheduling + +A time stamp is a specification of a date (possibly with time or a range +of times) in a special format, either @samp{<2003-09-16 Tue>} or +@samp{<2003-09-16 Tue 09:39>} or @samp{<2003-09-16 Tue +12:00-12:30>}@footnote{This is the standard ISO date/time format. To +use an alternative format, see @ref{Custom time format}.}. A time stamp +can appear anywhere in the headline or body of an org-tree entry. Its +presence causes entries to be shown on specific dates in the agenda +(@pxref{Weekly/Daily agenda}). We distinguish: + +@table @var +@item Plain time stamp; Event; Appointment +@cindex timestamp +A simple time stamp just assigns a date/time to an item. This is just +like writing down an appointment or event in a paper agenda. In the +timeline and agenda displays, the headline of an entry associated with a +plain time stamp will be shown exactly on that date. + +@example +* Meet Peter at the movies <2006-11-01 Wed 19:15> +* Discussion on climate change <2006-11-02 Thu 20:00-22:00> +@end example + +@item Time stamp with repeater interval +@cindex timestamp, with repeater interval +A time stamp may contain a @emph{repeater interval}, indicating that it +applies not only on the given date, but again and again after a certain +interval of N days (d), weeks (w), months(m), or years(y). The +following will show up in the agenda every Wednesday: + +@example +* Pick up Sam at school <2007-05-16 Wed 12:30 +1w> +@end example + +@item Diary-style sexp entries +For more complex date specifications, Org-mode supports using the +special sexp diary entries implemented in the Emacs calendar/diary +package. For example + +@example +* The nerd meeting on every 2nd Thursday of the month + <%%(diary-float t 4 2)> +@end example + +@item Time/Date range +@cindex timerange +@cindex date range +Two time stamps connected by @samp{--} denote a range. The headline +will be shown on the first and last day of the range, and on any dates +that are displayed and fall in the range. Here is an example: + +@example +** Meeting in Amsterdam + <2004-08-23 Mon>--<2004-08-26 Thu> +@end example + +@item Inactive time stamp +@cindex timestamp, inactive +@cindex inactive timestamp +Just like a plain time stamp, but with square brackets instead of +angular ones. These time stamps are inactive in the sense that they do +@emph{not} trigger an entry to show up in the agenda. + +@example +* Gillian comes late for the fifth time [2006-11-01 Wed] +@end example + +@end table + +@node Creating timestamps, Deadlines and scheduling, Time stamps, Dates and times +@section Creating timestamps +@cindex creating timestamps +@cindex timestamps, creating + +For Org-mode to recognize time stamps, they need to be in the specific +format. All commands listed below produce time stamps in the correct +format. + +@table @kbd +@kindex C-c . +@item C-c . +Prompt for a date and insert a corresponding time stamp. When the +cursor is at a previously used time stamp, it is updated to NOW. When +this command is used twice in succession, a time range is inserted. +@c +@kindex C-u C-c . +@item C-u C-c . +Like @kbd{C-c .}, but use the alternative format which contains date +and time. The default time can be rounded to multiples of 5 minutes, +see the option @code{org-time-stamp-rounding-minutes}. +@c +@kindex C-c ! +@item C-c ! +Like @kbd{C-c .}, but insert an inactive time stamp that will not cause +an agenda entry. +@c +@kindex C-c < +@item C-c < +Insert a time stamp corresponding to the cursor date in the Calendar. +@c +@kindex C-c > +@item C-c > +Access the Emacs calendar for the current date. If there is a +timestamp in the current line, goto the corresponding date +instead. +@c +@kindex C-c C-o +@item C-c C-o +Access the agenda for the date given by the time stamp or -range at +point (@pxref{Weekly/Daily agenda}). +@c +@kindex S-@key{left} +@kindex S-@key{right} +@item S-@key{left} +@itemx S-@key{right} +Change date at cursor by one day. These key bindings conflict with +CUA-mode (@pxref{Conflicts}). +@c +@kindex S-@key{up} +@kindex S-@key{down} +@item S-@key{up} +@itemx S-@key{down} +Change the item under the cursor in a timestamp. The cursor can be on a +year, month, day, hour or minute. Note that if the cursor is in a +headline and not at a time stamp, these same keys modify the priority of +an item. (@pxref{Priorities}). The key bindings also conflict with +CUA-mode (@pxref{Conflicts}). +@c +@kindex C-c C-y +@cindex evaluate time range +@item C-c C-y +Evaluate a time range by computing the difference between start and +end. With prefix arg, insert result after the time range (in a table: +into the following column). +@end table + + +@menu +* The date/time prompt:: How org-mode helps you entering date and time +* Custom time format:: Making dates look differently +@end menu + +@node The date/time prompt, Custom time format, Creating timestamps, Creating timestamps +@subsection The date/time prompt +@cindex date, reading in minibuffer +@cindex time, reading in minibuffer + +When Org-mode prompts for a date/time, the default is shown as an ISO +date, and the prompt therefore seems to ask for an ISO date. But it +will in fact accept any string containing some date and/or time +information, and it is really smart about interpreting your input. You +can, for example, use @kbd{C-y} to paste a (possibly multi-line) string +copied from an email message. Org-mode will find whatever information +is in there and derive anything you have not specified from the +@emph{default date and time}. The default is usually the current date +and time, but when modifying an existing time stamp, or when entering +the second stamp of a range, it is taken from the stamp in the buffer. +When filling in information, Org-mode assumes that most of the time you +will want to enter a date in the future: If you omit the month/year and +the given day/month is @i{before} today, it will assume that you mean a +future date@footnote{See the variable +@code{org-read-date-prefer-future}.}. + +For example, lets assume that today is @b{June 13, 2006}. Here is how +various inputs will be interpreted, the items filled in by Org-mode are +in @b{bold}. + +@example +3-2-5 --> 2003-02-05 +14 --> @b{2006}-@b{06}-14 +12 --> @b{2006}-@b{07}-12 +Fri --> nearest Friday (defaultdate or later) +sep 15 --> @b{2006}-11-15 +feb 15 --> @b{2007}-02-15 +sep 12 9 --> 2009-09-12 +12:45 --> @b{2006}-@b{06}-@b{13} 12:45 +22 sept 0:34 --> @b{2006}-09-22 0:34 +@end example + +Furthermore you can specify a relative date by giving, as the +@emph{first} thing in the input: a plus/minus sign, a number and a +letter [dwmy] to indicate change in days weeks, months, years. With a +single plus or minus, the date is always relative to today. With a +double plus or minus, it is relative to the default date. If instead of +a single letter, you use the abbreviation of day name, the date will be +the nth such day. E.g. + +@example ++4d --> four days from today ++4 --> same as above ++2w --> two weeks from today +++5 --> five days from default date ++2tue --> second tuesday from now. +@end example + +The function understands English month and weekday abbreviations. If +you want to use unabbreviated names and/or other languages, configure +the variables @code{parse-time-months} and @code{parse-time-weekdays}. + +@cindex calendar, for selecting date +Parallel to the minibuffer prompt, a calendar is popped up@footnote{If +you don't need/want the calendar, configure the variable +@code{org-popup-calendar-for-date-prompt}.}. When you exit the date +prompt, either by clicking on a date in the calendar, or by pressing +@key{RET}, the date selected in the calendar will be combined with the +information entered at the prompt. You can control the calendar fully +from the minibuffer: + +@kindex < +@kindex > +@kindex mouse-1 +@kindex S-@key{right} +@kindex S-@key{left} +@kindex S-@key{down} +@kindex S-@key{up} +@kindex M-S-@key{right} +@kindex M-S-@key{left} +@kindex @key{RET} +@example +> / < @r{Scroll calendar forward/backward by one month.} +mouse-1 @r{Select date by clicking on it.} +S-@key{right}/@key{left} @r{One day forward/backward.} +S-@key{down}/@key{up} @r{One week forward/backward.} +M-S-@key{right}/@key{left} @r{One month forward/backward.} +@key{RET} @r{Choose date in calendar.} +@end example + +The actions of the date/time prompt may seem complex, but I asure you +they will grow on you. To help you understand what is going on, the +current interpretation of your input will be displayed live in the +minibuffer@footnote{If you find this distracting, turn the display of +with @code{org-read-date-display-live}.}. + +@node Custom time format, , The date/time prompt, Creating timestamps +@subsection Custom time format +@cindex custom date/time format +@cindex time format, custom +@cindex date format, custom + +Org-mode uses the standard ISO notation for dates and times as it is +defined in ISO 8601. If you cannot get used to this and require another +representation of date and time to keep you happy, you can get it by +customizing the variables @code{org-display-custom-times} and +@code{org-time-stamp-custom-formats}. + +@table @kbd +@kindex C-c C-x C-t +@item C-c C-x C-t +Toggle the display of custom formats for dates and times. +@end table + +@noindent +Org-mode needs the default format for scanning, so the custom date/time +format does not @emph{replace} the default format - instead it is put +@emph{over} the default format using text properties. This has the +following consequences: +@itemize @bullet +@item +You cannot place the cursor onto a time stamp anymore, only before or +after. +@item +The @kbd{S-@key{up}/@key{down}} keys can no longer be used to adjust +each component of a time stamp. If the cursor is at the beginning of +the stamp, @kbd{S-@key{up}/@key{down}} will change the stamp by one day, +just like @kbd{S-@key{left}/@key{right}}. At the end of the stamp, the +time will be changed by one minute. +@item +If the time stamp contains a range of clock times or a repeater, these +will not be overlayed, but remain in the buffer as they were. +@item +When you delete a time stamp character-by-character, it will only +disappear from the buffer after @emph{all} (invisible) characters +belonging to the ISO timestamp have been removed. +@item +If the custom time stamp format is longer than the default and you are +using dates in tables, table alignment will be messed up. If the custom +format is shorter, things do work as expected. +@end itemize + + +@node Deadlines and scheduling, Clocking work time, Creating timestamps, Dates and times +@section Deadlines and Scheduling + +A time stamp may be preceded by special keywords to facilitate planning: + +@table @var +@item DEADLINE +@cindex DEADLINE keyword + +Meaning: the task (most likely a TODO item, though not necessarily) is supposed +to be finished on that date. + +On the deadline date, the task will be listed in the agenda. In +addition, the agenda for @emph{today} will carry a warning about the +approaching or missed deadline, starting +@code{org-deadline-warning-days} before the due date, and continuing +until the entry is marked DONE. An example: + +@example +*** TODO write article about the Earth for the Guide + The editor in charge is [[bbdb:Ford Prefect]] + DEADLINE: <2004-02-29 Sun> +@end example + +You can specify a different lead time for warnings for a specific +deadlines using the following syntax. Here is an example with a warning +period of 5 days @code{DEADLINE: <2004-02-29 Sun -5d>}. + +@item SCHEDULED +@cindex SCHEDULED keyword + +Meaning: you are planning to start working on that task on the given +date. + +The headline will be listed under the given date@footnote{It will still +be listed on that date after it has been marked DONE. If you don't like +this, set the variable @code{org-agenda-skip-scheduled-if-done}.}. In +addition, a reminder that the scheduled date has passed will be present +in the compilation for @emph{today}, until the entry is marked DONE. +I.e., the task will automatically be forwarded until completed. + +@example +*** TODO Call Trillian for a date on New Years Eve. + SCHEDULED: <2004-12-25 Sat> +@end example + +@noindent +@b{Important:} Scheduling an item in Org-mode should @i{not} be +understood in the same way that we understand @i{scheduling a meeting}. +Setting a date for a meeting is just a simple appointment, you should +mark this entry with a simple plain time stamp, to get this item shown +on the date where it applies. This is a frequent mis-understanding from +Org-users. In Org-mode, @i{scheduling} means setting a date when you +want to start working on an action item. +@end table + +You may use time stamps with repeaters in scheduling and deadline +entries. Org-mode will issue early and late warnings based on the +assumption that the time stamp represents the @i{nearest instance} of +the repeater. However, the use of diary sexp entries like +@c +@code{<%%(diary-float t 42)>} +@c +in scheduling and deadline timestamps is limited. Org-mode does not +know enough about the internals of each sexp function to issue early and +late warnings. However, it will show the item on each day where the +sexp entry matches. + +@menu +* Inserting deadline/schedule:: Planning items +* Repeated tasks:: Items that show up again and again +@end menu + +@node Inserting deadline/schedule, Repeated tasks, Deadlines and scheduling, Deadlines and scheduling +@subsection Inserting deadline/schedule + +The following commands allow to quickly insert a deadline or to schedule +an item: + +@table @kbd +@c +@kindex C-c C-d +@item C-c C-d +Insert @samp{DEADLINE} keyword along with a stamp. The insertion will +happen in the line directly following the headline. When called with a +prefix arg, an existing deadline will be removed from the entry. +@c FIXME Any CLOSED timestamp will be removed.???????? +@c +@kindex C-c / d +@cindex sparse tree, for deadlines +@item C-c / d +Create a sparse tree with all deadlines that are either past-due, or +which will become due within @code{org-deadline-warning-days}. +With @kbd{C-u} prefix, show all deadlines in the file. With a numeric +prefix, check that many days. For example, @kbd{C-1 C-c / d} shows +all deadlines due tomorrow. +@c +@kindex C-c C-s +@item C-c C-s +Insert @samp{SCHEDULED} keyword along with a stamp. The insertion will +happen in the line directly following the headline. Any CLOSED +timestamp will be removed. When called with a prefix argument, remove +the scheduling date from the entry. +@end table + +@node Repeated tasks, , Inserting deadline/schedule, Deadlines and scheduling +@subsection Repeated Tasks + +Some tasks need to be repeated again and again. Org-mode helps to +organize such tasks using a so-called repeater in a DEADLINE, SCHEDULED, +or plain time stamp. In the following example +@example +** TODO Pay the rent + DEADLINE: <2005-10-01 Sat +1m> +@end example +the @code{+1m} is a repeater; the intended interpretation is that the +task has a deadline on <2005-10-01> and repeats itself every (one) month +starting from that time. If you need both a repeater and a special +warning period in a deadline entry, the repeater comes first and the +warning period last: @code{DEADLINE: <2005-10-01 Sat +1m -3d>}. + +Deadlines and scheduled items produce entries in the agenda when they +are over-due, so it is important to be able to mark such an entry as +completed once you have done so. When you mark a DEADLINE or a SCHEDULE +with the todo keyword DONE, it will no longer produce entries in the +agenda. The problem with this is, however, that then also the +@emph{next} instance of the repeated entry will not be active. Org-mode +deals with this in the following way: When you try to mark such an entry +DONE (using @kbd{C-c C-t}), it will shift the base date of the repeating +time stamp by the repeater interval, and immediately set the entry state +back to TODO. In the example above, setting the state to DONE would +actually switch the date like this: + +@example +** TODO Pay the rent + DEADLINE: <2005-11-01 Tue +1m> +@end example + +You will also be prompted for a note@footnote{You can change this using +the option @code{org-log-repeat}, or the @code{#+STARTUP} options +@code{logrepeat}, @code{lognoterepeat}, and @code{nologrepeat}.} that +will be put under the DEADLINE line to keep a record that you actually +acted on the previous instance of this deadline. + +As a consequence of shifting the base date, this entry will no longer be +visible in the agenda when checking past dates, but all future instances +will be visible. + +With the @samp{+1m} cookie, the date shift will always be exactly one +month. So if you have not payed the rent for three months, marking this +entry DONE will still keep it as an overdue deadline. Depending on the +task, this may not be the best way to handle it. For example, if you +forgot to call you father for 3 weeks, it does not make sense to call +her 3 times in a single day to make up for it. Finally, there are tasks +like changing batteries which should always repeat a certain time +@i{after} the last time you did it. For these tasks, Org-mode has +special repeaters markes with @samp{++} and @samp{.+}. For example: + +@example +** TODO Call Father + DEADLINE: <2008-02-10 Sun ++1w> + Marking this DONE will shift the date by at least one week, + but also by as many weeks as it takes to get this date into + the future. However, it stays on a Sunday, even if you called + and marked it done on Saturday. +** TODO Check the batteries in the smoke detectors + DEADLINE: <2005-11-01 Tue .+1m> + Marking this DONE will shift the date to one month after + today. +@end example + +You may have both scheduling and deadline information for a specific +task - just make sure that the repeater intervals on both are the same. + +@node Clocking work time, , Deadlines and scheduling, Dates and times +@section Clocking work time + +Org-mode allows you to clock the time you spent on specific tasks in a +project. When you start working on an item, you can start the clock. +When you stop working on that task, or when you mark the task done, the +clock is stopped and the corresponding time interval is recorded. It +also computes the total time spent on each subtree of a project. + +@table @kbd +@kindex C-c C-x C-i +@item C-c C-x C-i +Start the clock on the current item (clock-in). This inserts the CLOCK +keyword together with a timestamp. If this is not the first clocking of +this item, the multiple CLOCK lines will be wrapped into a +@code{:CLOCK:} drawer (see also the variable +@code{org-clock-into-drawer}). +@kindex C-c C-x C-o +@item C-c C-x C-o +Stop the clock (clock-out). The inserts another timestamp at the same +location where the clock was last started. It also directly computes +the resulting time in inserts it after the time range as @samp{=> +HH:MM}. See the variable @code{org-log-note-clock-out} for the +possibility to record an additional note together with the clock-out +time stamp@footnote{The corresponding in-buffer setting is: +@code{#+STARTUP: lognoteclock-out}}. +@kindex C-c C-y +@item C-c C-y +Recompute the time interval after changing one of the time stamps. This +is only necessary if you edit the time stamps directly. If you change +them with @kbd{S-@key{cursor}} keys, the update is automatic. +@kindex C-c C-t +@item C-c C-t +Changing the TODO state of an item to DONE automatically stops the clock +if it is running in this same item. +@kindex C-c C-x C-x +@item C-c C-x C-x +Cancel the current clock. This is useful if a clock was started by +mistake, or if you ended up working on something else. +@kindex C-c C-x C-j +@item C-c C-x C-j +Jump to the entry that contains the currently running clock, an another +window. +@kindex C-c C-x C-d +@item C-c C-x C-d +Display time summaries for each subtree in the current buffer. This +puts overlays at the end of each headline, showing the total time +recorded under that heading, including the time of any subheadings. You +can use visibility cycling to study the tree, but the overlays disappear +when you change the buffer (see variable +@code{org-remove-highlights-with-change}) or press @kbd{C-c C-c}. +@kindex C-c C-x C-r +@item C-c C-x C-r +Insert a dynamic block (@pxref{Dynamic blocks}) containing a clock +report as an org-mode table into the current file. When the cursor is +at an existing clock table, just update it. When called with a prefix +argument, jump to the first clock report in the current document and +update it. +@example +#+BEGIN: clocktable :maxlevel 2 :emphasize nil :scope file + +#+END: clocktable +@end example +@noindent +If such a block already exists at point, its content is replaced by the +new table. The @samp{BEGIN} line can specify options: +@example +:maxlevel @r{Maximum level depth to which times are listed in the table.} +:emphasize @r{When @code{t}, emphasize level one and level two items} +:scope @r{The scope to consider. This can be any of the following:} + nil @r{the current buffer or narrowed region} + file @r{the full current buffer} + subtree @r{the subtree where the clocktable is located} + treeN @r{the surrounding level N tree, for example @code{tree3}} + tree @r{the surrounding level 1 tree} + agenda @r{all agenda files} + ("file"..) @r{scan these files} +:block @r{The time block to consider. This block is specified relative} + @r{to the current time and may be any of these keywords:} + @r{@code{today}, @code{yesterday}, @code{thisweek}, @code{lastweek},} + @r{@code{thismonth}, @code{lastmonth}, @code{thisyear}, or @code{lastyear}}. +:tstart @r{A time string specifying when to start considering times} +:tend @r{A time string specifying when to stop considering times} +:step @r{@code{week} or @code{day}, to split the table into chunks} +:link @r{Link the item headlines in the table to their origins} +@end example +So to get a clock summary of the current level 1 tree, for the current +day, you could write +@example +#+BEGIN: clocktable :maxlevel 2 :block today :scope tree1 + +#+END: clocktable +@end example +and to use a specific time range you could write@footnote{Note that all +parameters must be specified in a single line - the line is broken here +only to fit it onto the manual.} +@example +#+BEGIN: clocktable :tstart "<2006-08-10 Thu 10:00>" + :tend "<2006-08-10 Thu 12:00>" + +#+END: clocktable +@end example +@kindex C-c C-c +@item C-c C-c +@kindex C-c C-x C-u +@itemx C-c C-x C-u +Update dynamical block at point. The cursor needs to be in the +@code{#+BEGIN} line of the dynamic block. +@kindex C-u C-c C-x C-u +@item C-u C-c C-x C-u +Update all dynamic blocks (@pxref{Dynamic blocks}). This is useful if +you have several clocktable blocks in a buffer. +@end table + +The @kbd{l} key may be used in the timeline (@pxref{Timeline}) and in +the agenda (@pxref{Weekly/Daily agenda}) to show which tasks have been +worked on or closed during a day. + +@node Remember, Agenda views, Dates and times, Top +@chapter Remember +@cindex @file{remember.el} + +The @i{Remember} package by John Wiegley lets you store quick notes with +little interruption of your work flow. See +@uref{http://www.emacswiki.org/cgi-bin/wiki/RememberMode} for more +information. It is an excellent way to add new notes and tasks to +Org-mode files. Org-mode significantly expands the possibilities of +@i{remember}: You may define templates for different note types, and +associate target files and headlines with specific templates. It also +allows you to select the location where a note should be stored +interactively, on the fly. + +@menu +* Setting up remember:: Some code for .emacs to get things going +* Remember templates:: Define the outline of different note types +* Storing notes:: Directly get the note to where it belongs +* Refiling notes:: Moving a note or task to a project +@end menu + +@node Setting up remember, Remember templates, Remember, Remember +@section Setting up remember + +The following customization will tell @i{remember} to use org files as +target, and to create annotations compatible with Org-mode links. + +@example +(org-remember-insinuate) +(setq org-directory "~/path/to/my/orgfiles/") +(setq org-default-notes-file (concat org-directory "/notes.org")) +(define-key global-map "\C-cr" 'org-remember) +@end example + +The last line binds the command @code{org-remember} to a global +key@footnote{Please select your own key, @kbd{C-c r} is only a +suggestion.}. @code{org-remember} basically just calls @code{remember}, +but it makes a few things easier: If there is an active region, it will +automatically copy the region into the remember buffer. It also allows +to jump to the buffer and location where remember notes are being +stored: Just call @code{org-remember} with a prefix argument. If you +use two prefix arguments, Org-mode jumps to the location where the last +remember note was stored. + +@node Remember templates, Storing notes, Setting up remember, Remember +@section Remember templates +@cindex templates, for remember + +In combination with Org-mode, you can use templates to generate +different types of @i{remember} notes. For example, if you would like +to use one template to create general TODO entries, another one for +journal entries, and a third one for collecting random ideas, you could +use: + +@example +(setq org-remember-templates + '(("Todo" ?t "* TODO %?\n %i\n %a" "~/org/TODO.org" "Tasks") + ("Journal" ?j "* %U %?\n\n %i\n %a" "~/org/JOURNAL.org") + ("Idea" ?i "* %^@{Title@}\n %i\n %a" "~/org/JOURNAL.org" "New Ideas"))) +@end example + +@noindent In these entries, the first string is just a name, and the +character specifies how to select the template. It is useful if the +character is also the first letter of the name. The next string +specifies the template. Two more (optional) strings give the file in +which, and the headline under which the new note should be stored. The +file (if not present or @code{nil}) defaults to +@code{org-default-notes-file}, the heading to +@code{org-remember-default-headline}. + +An optional sixth element specifies the contexts in which the user can +select the template. This element can be either a list of major modes +or a function. @code{org-remember} will first check whether the function +returns @code{t} or if we are in any of the listed major mode, and select +the template accordingly. + +So for example: + +@example +(setq org-remember-templates + '(("Bug" ?b "* BUG %?\n %i\n %a" "~/org/BUGS.org" "Bugs" (emacs-lisp-mode)) + ("Journal" ?j "* %U %?\n\n %i\n %a" "~/org/JOURNAL.org" my-check) + ("Idea" ?i "* %^@{Title@}\n %i\n %a" "~/org/JOURNAL.org" "New Ideas"))) +@end example + +The first template will only be available when invoking @code{org-remember} +from an buffer in @code{emacs-lisp-mode}. The second template will only be +available when the function @code{my-check} returns @code{t}. The third +template will be proposed in any context. + +When you call @kbd{M-x remember} (or @kbd{M-x org-remember}) to remember +something, org will prompt for a key to select the template (if you have +more than one template) and then prepare the buffer like +@example +* TODO + [[file:link to where you called remember]] +@end example + +@noindent +During expansion of the template, special @kbd{%}-escapes allow dynamic +insertion of content: +@example +%^@{prompt@} @r{prompt the user for a string and replace this sequence with it.} + @r{You may specify a default value and a completion table with} + @r{%^@{prompt|default|completion2|completion3...@}} + @r{The arrow keys access a prompt-specific history.} +%t @r{time stamp, date only} +%T @r{time stamp with date and time} +%u, %U @r{like the above, but inactive time stamps} +%^t @r{like @code{%t}, but prompt for date. Similarly @code{%^T}, @code{%^u}, @code{%^U}} + @r{You may define a prompt like @code{%^@{Birthday@}t}} +%n @r{user name (taken from @code{user-full-name})} +%a @r{annotation, normally the link created with @code{org-store-link}} +%A @r{like @code{%a}, but prompt for the description part} +%i @r{initial content, the region when remember is called with C-u.} + @r{The entire text will be indented like @code{%i} itself.} +%c @r{Content of the clipboard, or current kill ring head.} +%^g @r{prompt for tags, with completion on tags in target file.} +%^G @r{prompt for tags, with completion all tags in all agenda files.} +%:keyword @r{specific information for certain link types, see below} +%[pathname] @r{insert the contents of the file given by @code{pathname}} +%(sexp) @r{evaluate elisp @code{(sexp)} and replace with the result} +%! @r{immediately store note after completing the template} + @r{(skipping the @kbd{C-c C-c} that normally triggers storing)} +@end example + +@noindent +For specific link types, the following keywords will be +defined@footnote{If you define your own link types (@pxref{Adding +hyperlink types}), any property you store with +@code{org-store-link-props} can be accessed in remember templates in a +similar way.}: + +@example +Link type | Available keywords +-------------------+---------------------------------------------- +bbdb | %:name %:company +bbdb | %::server %:port %:nick +vm, wl, mh, rmail | %:type %:subject %:message-id + | %:from %:fromname %:fromaddress + | %:to %:toname %:toaddress + | %:fromto @r{(either "to NAME" or "from NAME")@footnote{This will always be the other, not the user. See the variable @code{org-from-is-user-regexp}.}} +gnus | %:group, @r{for messages also all email fields} +w3, w3m | %:url +info | %:file %:node +calendar | %:date" +@end example + +@noindent +To place the cursor after template expansion use: + +@example +%? @r{After completing the template, position cursor here.} +@end example + +@noindent +If you change your mind about which template to use, call +@code{org-remember} in the remember buffer. You may then select a new +template that will be filled with the previous context information. + +@node Storing notes, Refiling notes, Remember templates, Remember +@section Storing notes + +When you are finished preparing a note with @i{remember}, you have to +press @kbd{C-c C-c} to file the note away. The handler will store the +note in the file and under the headline specified in the template, or it +will use the default file and headlines. The window configuration will +be restored, sending you back to the working context before the call to +@code{remember}. To re-use the location found during the last call to +@code{remember}, exit the remember buffer with @kbd{C-u C-u C-c C-c}, +i.e. specify a double prefix argument to @kbd{C-c C-c}. + +If you want to store the note directly to a different place, use +@kbd{C-u C-c C-c} instead to exit remember@footnote{Configure the +variable @code{org-remember-store-without-prompt} to make this behavior +the default.}. The handler will then first prompt for a target file - +if you press @key{RET}, the value specified for the template is used. +Then the command offers the headings tree of the selected file, with the +cursor position at the default headline (if you had specified one in the +template). You can either immediately press @key{RET} to get the note +placed there. Or you can use the following keys to find a different +location: +@example +@key{TAB} @r{Cycle visibility.} +@key{down} / @key{up} @r{Next/previous visible headline.} +n / p @r{Next/previous visible headline.} +f / b @r{Next/previous headline same level.} +u @r{One level up.} +@c 0-9 @r{Digit argument.} +@end example +@noindent +Pressing @key{RET} or @key{left} or @key{right} +then leads to the following result. + +@multitable @columnfractions 0.2 0.15 0.65 +@item @b{Cursor position} @tab @b{Key} @tab @b{Note gets inserted} +@item on headline @tab @key{RET} @tab as sublevel of the heading at cursor, first or last +@item @tab @tab depending on @code{org-reverse-note-order}. +@item @tab @key{left}/@key{right} @tab as same level, before/after current heading +@item buffer-start @tab @key{RET} @tab as level 2 heading at end of file or level 1 at beginning +@item @tab @tab depending on @code{org-reverse-note-order}. +@item not on headline @tab @key{RET} + @tab at cursor position, level taken from context. +@end multitable + +Before inserting the text into a tree, the function ensures that the +text has a headline, i.e. a first line that starts with a @samp{*}. If +not, a headline is constructed from the current date and some additional +data. If you have indented the text of the note below the headline, the +indentation will be adapted if inserting the note into the tree requires +demotion from level 1. + +@node Refiling notes, , Storing notes, Remember +@section Refiling notes +@cindex refiling notes + +Remember is usually used to quickly capture notes and tasks into one or +a few capture lists. When reviewing the captured data, you may want to +refile some of the entries into a different list, for example into a +project. Cutting, finding the right location and then pasting the note +is cumbersome. To simplify this process, you can use the following +special command: + +@table @kbd +@kindex C-c C-w +@item C-c C-w +Refile the entry at point. This command offers possible locations for +refiling the entry and lets you select one with completion. The item is +filed below the target heading as a subitem. Depending on +@code{org-reverse-note-order}, it will be either the first of last +subitem.@* By default, all level 1 headlines in the current buffer are +considered to be targets, but you can have more complex definitions +across a number of files. See the variable @code{org-refile-targets} +for details. +@kindex C-u C-c C-w +@item C-u C-c C-w +Use the refile interface to jump to a heading. +@kindex C-u C-u C-c C-w +@item C- C-u C-c C-w +Jump to the location where @code{org-refile} last moved a tree to. +@end table + +@node Agenda views, Embedded LaTeX, Remember, Top @chapter Agenda Views @cindex agenda views Due to the way Org-mode works, TODO items, time-stamped items, and tagged headlines can be scattered throughout a file or even a number of -files. To get an overview over open action items, or over events that -are important for a particular date, this information must be collected, +files. To get an overview of open action items, or of events that are +important for a particular date, this information must be collected, sorted and displayed in an organized way. Org-mode can select items based on various criteria, and display them -in a separate buffer. Six different view types are provided: +in a separate buffer. Seven different view types are provided: @itemize @bullet @item @@ -3573,6 +4810,9 @@ the tags associated with them, a @emph{timeline view} that shows all events in a single Org-mode file, in time-sorted view, @item +a @emph{keyword search view} that shows all entries from multiple files +that contain specified keywords. +@item a @emph{stuck projects view} showing projects that currently don't move along, and @item @@ -3584,7 +4824,7 @@ combinations of different views. The extracted information is displayed in a special @emph{agenda buffer}. This buffer is read-only, but provides commands to visit the corresponding locations in the original Org-mode files, and even to -edit these files remotely. +edit these files remotely. Two variables control how the agenda buffer is displayed and whether the window configuration is restored when the agenda exits: @@ -3605,14 +4845,18 @@ window configuration is restored when the agenda exits: @cindex agenda files @cindex files for agenda -The information to be shown is collected from all @emph{agenda files}, -the files listed in the variable @code{org-agenda-files}@footnote{If the -value of that variable is not a list, but a single file name, then the -list of agenda files will be maintained in that external file.}. Thus even -if you only work with a single Org-mode file, this file should be put -into that list@footnote{When using the dispatcher, pressing @kbd{1} -before selecting a command will actually limit the command to the -current file, and ignore @code{org-agenda-files} until the next +The information to be shown is normally collected from all @emph{agenda +files}, the files listed in the variable +@code{org-agenda-files}@footnote{If the value of that variable is not a +list, but a single file name, then the list of agenda files will be +maintained in that external file.}. If a directory is part of this list, +all files with the extension @file{.org} in this directory will be part +of the list. + +Thus even if you only work with a single Org-mode file, this file should +be put into that list@footnote{When using the dispatcher, pressing +@kbd{<} before selecting a command will actually limit the command to +the current file, and ignore @code{org-agenda-files} until the next dispatcher command.}. You can customize @code{org-agenda-files}, but the easiest way to maintain it is through the following commands @@ -3637,6 +4881,42 @@ Cycle through agenda file list, visiting one file after the other. The Org menu contains the current list of files and can be used to visit any of them. +If you would like to focus the agenda temporarily onto a file not in +this list, or onto just one file in the list or even only a subtree in a +file, this can be done in different ways. For a single agenda command, +you may press @kbd{<} once or several times in the dispatcher +(@pxref{Agenda dispatcher}). To restrict the agenda scope for an +extended period, use the following commands: + +@table @kbd +@kindex C-c C-x < +@item C-c C-x < +Permanently restrict the agenda to the current subtree. When with a +prefix argument, or with the cursor before the first headline in a file, +the agenda scope is set to the entire file. This restriction remains in +effect until removed with @kbd{C-c C-x >}, or by typing either @kbd{<} +or @kbd{>} in the agenda dispatcher. If there is a window displaying an +agenda view, the new restriction takes effect immediately. +@kindex C-c C-x < +@item C-c C-x < +Remove the permanent restriction created by @kbd{C-c C-x <}. +@end table + +@noindent +When working with @file{Speedbar}, you can use the following commands in +the speedbar frame: +@table @kbd +@kindex < +@item < @r{in the speedbar frame} +Permanently restrict the agenda to the item at the cursor in the +speedbar frame, either an Org-mode file or a subtree in such a file. +If there is a window displaying an agenda view, the new restriction takes +effect immediately. +@kindex < +@item > @r{in the speedbar frame} +Lift the restriction again. +@end table + @node Agenda dispatcher, Built-in agenda views, Agenda files, Agenda views @section The agenda dispatcher @cindex agenda dispatcher @@ -3654,19 +4934,31 @@ Create the calendar-like agenda (@pxref{Weekly/Daily agenda}). Create a list of all TODO items (@pxref{Global TODO list}). @item m @r{/} M Create a list of headlines matching a TAGS expression (@pxref{Matching -headline tags}). +tags and properties}). @item L Create the timeline view for the current buffer (@pxref{Timeline}). +@item s +Create a list of entries selected by a boolean expression of keywords +and/or regular expressions that must or must not occur in the entry. +@item / +Search for a regular expression in all agenda files and additionally in +the files listed in @code{org-agenda-multi-occur-extra-files}. This +uses the Emacs command @code{multi-occur}. A prefix argument can be +used to specify the number of context lines for each match, default is +1. @item # @r{/} ! Create a list of stuck projects (@pxref{Stuck projects}). -@item 1 -Restrict an agenda command to the current buffer. After pressing -@kbd{1}, you still need to press the character selecting the command. -@item 0 +@item < +Restrict an agenda command to the current buffer@footnote{For backward +compatibility, you can also press @kbd{1} to restrict to the current +buffer.}. After pressing @kbd{<}, you still need to press the character +selecting the command. +@item < < If there is an active region, restrict the following agenda command to -the region. Otherwise, restrict it to the current subtree. After -pressing @kbd{0}, you still need to press the character selecting the -command. +the region. Otherwise, restrict it to the current subtree@footnote{For +backward compatibility, you can also press @kbd{0} to restrict to the +current buffer.}. After pressing @kbd{< <}, you still need to press the +character selecting the command. @end table You can also define custom commands that will be accessible through the @@ -3683,8 +4975,9 @@ In this section we describe the built-in views. @menu * Weekly/Daily agenda:: The calendar page with current tasks * Global TODO list:: All unfinished action items -* Matching headline tags:: Structured information with fine-tuned search +* Matching tags and properties:: Structured information with fine-tuned search * Timeline:: Time-sorted view for single file +* Keyword search:: Finding entries by keyword * Stuck projects:: Find projects you need to review @end menu @@ -3702,10 +4995,12 @@ paper agenda, showing all the tasks for the current week or day. @kindex C-c a a @item C-c a a Compile an agenda for the current week from a list of org files. The -agenda shows the entries for each day. With a @kbd{C-u} prefix (or -when the variable @code{org-agenda-include-all-todo} is @code{t}), all -unfinished TODO items (including those without a date) are also listed at -the beginning of the buffer, before the first date.@* +agenda shows the entries for each day. With a numeric +prefix@footnote{For backward compatibility, the universal prefix +@kbd{C-u} causes all TODO entries to be listed before the agenda. This +feature is deprecated, use the dedicated TODO list, or a block agenda +instead.} (like @kbd{C-u 2 1 C-c a a}) you may set the number of days +to be displayed (see also the variable @code{org-agenda-ndays}) @end table Remote editing from the agenda buffer means, for example, that you can @@ -3743,8 +5038,37 @@ Sunrise/Sunset times, show lunar phases and to convert to other calendars, respectively. @kbd{c} can be used to switch back and forth between calendar and agenda. +If you are using the diary only for sexp entries and holidays, it is +faster to not use the above setting, but instead to copy or even move +the entries into an Org-mode file. Org-mode evaluates diary-style sexp +entries, and does it faster because there is no overhead for first +creating the diary display. Note that the sexp entries must start at +the left margin, no white space is allowed before them. For example, +the following segment of an Org-mode file will be processed and entries +will be made in the agenda: -@node Global TODO list, Matching headline tags, Weekly/Daily agenda, Built-in agenda views +@example +* Birthdays and similar stuff +#+CATEGORY: Holiday +%%(org-calendar-holiday) ; special function for holiday names +#+CATEGORY: Ann +%%(diary-anniversary 14 5 1956) Arthur Dent is %d years old +%%(diary-anniversary 2 10 1869) Mahatma Gandhi would be %d years old +@end example + +@subsubheading Appointment reminders +@cindex @file{appt.el} +@cindex appointment reminders + +Org can interact with Emacs appointments notification facility. + +To add all the appointments of your agenda files, use the command +@code{org-agenda-to-appt}. This commands also lets you filter through +the list of your appointments and add only those belonging to a specific +category or matching a regular expression. See the docstring for +details. + +@node Global TODO list, Matching tags and properties, Weekly/Daily agenda, Built-in agenda views @subsection The global TODO list @cindex global TODO list @cindex TODO list, global @@ -3762,10 +5086,12 @@ the TODO entries directly from that buffer (@pxref{Agenda commands}). @kindex C-c a T @item C-c a T @cindex TODO keyword matching -Like the above, but allows selection of a specific TODO keyword. You can -also do this by specifying a prefix argument to @kbd{C-c a t}. With a -@kbd{C-u} prefix you are prompted for a keyword. With a numeric -prefix, the Nth keyword in @code{org-todo-keywords} is selected. +Like the above, but allows selection of a specific TODO keyword. You +can also do this by specifying a prefix argument to @kbd{C-c a t}. With +a @kbd{C-u} prefix you are prompted for a keyword, and you may also +specify several keywords by separating them with @samp{|} as boolean OR +operator. With a numeric prefix, the Nth keyword in +@code{org-todo-keywords} is selected. @kindex r The @kbd{r} key in the agenda buffer regenerates it, and you can give a prefix argument to this command to change the selected TODO keyword, @@ -3796,9 +5122,10 @@ and omit the sublevels from the global list. Configure the variable @code{org-agenda-todo-list-sublevels} to get this behavior. @end itemize -@node Matching headline tags, Timeline, Global TODO list, Built-in agenda views -@subsection Matching headline tags +@node Matching tags and properties, Timeline, Global TODO list, Built-in agenda views +@subsection Matching Tags and Properties @cindex matching, of tags +@cindex matching, of properties @cindex tags view If headlines in the agenda files are marked with @emph{tags} @@ -3810,8 +5137,8 @@ to them and collect them into an agenda buffer. @item C-c a m Produce a list of all headlines that match a given set of tags. The command prompts for a selection criterion, which is a boolean logic -expression with tags, like @samp{+WORK+URGENT-WITHBOSS} or -@samp{WORK|HOME} (@pxref{Tags}). If you often need a specific search, +expression with tags, like @samp{+work+urgent-withboss} or +@samp{work|home} (@pxref{Tags}). If you often need a specific search, define a custom command for it (@pxref{Agenda dispatcher}). @kindex C-c a M @item C-c a M @@ -3824,7 +5151,7 @@ together with a tags match is also possible, see @ref{Tag searches}. The commands available in the tags list are described in @ref{Agenda commands}. -@node Timeline, Stuck projects, Matching headline tags, Built-in agenda views +@node Timeline, Keyword search, Matching tags and properties, Built-in agenda views @subsection Timeline for a single file @cindex timeline, single file @cindex time-sorted view @@ -3834,7 +5161,7 @@ file in a @emph{time-sorted view}. The main purpose of this command is to give an overview over events in a project. @table @kbd -@kindex C-a a L +@kindex C-c a L @item C-c a L Show a time-sorted view of the org file, with all time-stamped items. When called with a @kbd{C-u} prefix, all unfinished TODO entries @@ -3845,8 +5172,36 @@ When called with a @kbd{C-u} prefix, all unfinished TODO entries The commands available in the timeline buffer are listed in @ref{Agenda commands}. +@node Keyword search, Stuck projects, Timeline, Built-in agenda views +@subsection Keyword search +@cindex keyword search +@cindex searching, for keywords -@node Stuck projects, , Timeline, Built-in agenda views +This agenda view is a general text search facility for Org-mode entries. +It is particularly useful to find notes. + +@table @kbd +@kindex C-c a s +@item C-c a s +This is a special search that lets you select entries by keywords or +regular expression, using a boolean logic. For example, the search +string + +@example ++computer +wifi -ethernet -@{8\.11[bg]@} +@end example + +@noindent +will search for note entries that contain the keywords @code{computer} +and @code{wifi}, but not the keyword @code{ethernet}, and which are also +not matched by the regular expression @code{8\.11[bg]}, meaning to +exclude both 8.11b and 8.11g. + +Note that in addition to the agenda files, this command will also search +the files listed in @code{org-agenda-text-search-extra-files}. +@end table + +@node Stuck projects, , Keyword search, Built-in agenda views @subsection Stuck projects If you are following a system like David Allen's GTD to organize your @@ -3875,16 +5230,18 @@ Lets assume that you, in your own way of using Org-mode, identify projects with a tag PROJECT, and that you use a todo keyword MAYBE to indicate a project that should not be considered yet. Lets further assume that the todo keyword DONE marks finished projects, and that NEXT -and TODO indicate next actions. Finally, the tag @@SHOP indicates -shopping and is a next action even without the NEXT tag. In this case -you would start by identifying eligible projects with a tags/todo match -@samp{+PROJECT/-MAYBE-DONE}, and then check for TODO, NEXT and @@SHOP in -the subtree to identify projects that are not stuck. The correct -customization for this is +and TODO indicate next actions. The tag @@SHOP indicates shopping and +is a next action even without the NEXT tag. Finally, if the project +contains the special word IGNORE anywhere, it should not be listed +either. In this case you would start by identifying eligible projects +with a tags/todo match @samp{+PROJECT/-MAYBE-DONE}, and then check for +TODO, NEXT, @@SHOP, and IGNORE in the subtree to identify projects that +are not stuck. The correct customization for this is @lisp (setq org-stuck-projects - ("+PROJECT/-MAYBE-DONE" ("NEXT" "TODO") ("@@SHOP"))) + '("+PROJECT/-MAYBE-DONE" ("NEXT" "TODO") ("@@SHOP") + "\\")) @end lisp @@ -3912,16 +5269,27 @@ associated with the item. @cindex category The category is a broad label assigned to each agenda item. By default, the category is simply derived from the file name, but you can also -specify it with a special line in the buffer, like this: +specify it with a special line in the buffer, like this@footnote{For +backward compatibility, the following also works: If there are several +such lines in a file, each specifies the category for the text below it. +The first category also applies to any text before the first CATEGORY +line. However, using this method is @emph{strongly} deprecated as it is +incompatible with the outline structure of the document. The correct +method for setting multiple categories in a buffer is using a +property.}: @example #+CATEGORY: Thesis @end example -If there are several such lines in a file, each specifies the category -for the text below it (but the first category also applies to any text -before the first CATEGORY line). The display in the agenda buffer looks -best if the category is not longer than 10 characters. +@noindent +If you would like to have a special CATEGORY for a single entry or a +(sub)tree, give the entry a @code{:CATEGORY:} property with the location +as the value (@pxref{Properties and columns}). + +@noindent +The display in the agenda buffer looks best if the category is not +longer than 10 characters. @node Time-of-day specifications, Sorting of agenda items, Categories, Presentation and sorting @subsection Time-of-Day Specifications @@ -3989,7 +5357,7 @@ Within each category, items are sorted by priority (@pxref{Priorities}), which is composed of the base priority (2000 for priority @samp{A}, 1000 for @samp{B}, and 0 for @samp{C}), plus additional increments for overdue scheduled or deadline items. -@item +@item For the TODO list, items remain in the order of categories, but within each category, sorting takes place according to priority (@pxref{Priorities}). @@ -4021,21 +5389,21 @@ the other commands, the cursor needs to be in the desired line. @cindex motion commands in agenda @kindex n @item n -Next line (same as @key{up}). +Next line (same as @key{up} and @kbd{C-p}). @kindex p @item p -Previous line (same as @key{down}). +Previous line (same as @key{down} and @kbd{C-n}). @tsubheading{View/GoTo org file} @kindex mouse-3 @kindex @key{SPC} @item mouse-3 @itemx @key{SPC} Display the original location of the item in another window. - +@c @kindex L @item L Display original location and recenter that window. - +@c @kindex mouse-2 @kindex mouse-1 @kindex @key{TAB} @@ -4044,11 +5412,11 @@ Display original location and recenter that window. @itemx @key{TAB} Go to the original location of the item in another window. Under Emacs 22, @kbd{mouse-1} will also works for this. - +@c @kindex @key{RET} @itemx @key{RET} Go to the original location of the item and delete other windows. - +@c @kindex f @item f Toggle Follow mode. In Follow mode, as you move the cursor through @@ -4056,14 +5424,14 @@ the agenda buffer, the other window always shows the corresponding location in the org file. The initial setting for this mode in new agenda buffers can be set with the variable @code{org-agenda-start-with-follow-mode}. - +@c @kindex b @item b Display the entire subtree of the current item in an indirect buffer. With numerical prefix ARG, go up to this level and then take that tree. If ARG is negative, go up that many levels. With @kbd{C-u} prefix, do not remove the previously used indirect buffer. - +@c @kindex l @item l Toggle Logbook mode. In Logbook mode, entries that where marked DONE while @@ -4075,24 +5443,25 @@ as are entries that have been clocked on that day. @kindex o @item o Delete other windows. - -@kindex w -@item w -Switch to weekly view (7 days displayed together). - +@c @kindex d -@item d -Switch to daily view (just one day displayed). - +@kindex w +@kindex m +@kindex y +@item d w m y +Switch to day/week/month/year view. When switching to day or week view, +this setting becomes the default for subseqent agenda commands. Since +month and year views are slow to create, the do not become the default. +@c @kindex D @item D Toggle the inclusion of diary entries. See @ref{Weekly/Daily agenda}. - -@kindex g -@item g +@c +@kindex G +@item G Toggle the time grid on and off. See also the variables @code{org-agenda-use-time-grid} and @code{org-agenda-time-grid}. - +@c @kindex r @item r Recreate the agenda buffer, for example to reflect the changes @@ -4100,77 +5469,100 @@ after modification of the time stamps of items with S-@key{left} and S-@key{right}. When the buffer is the global todo list, a prefix argument is interpreted to create a selective list for a specific TODO keyword. - +@kindex g +@item g +Same as @kbd{r}. +@c @kindex s +@kindex C-x C-s @item s +@itemx C-x C-s Save all Org-mode buffers in the current Emacs session. - +@c @kindex @key{right} @item @key{right} Display the following @code{org-agenda-ndays} days. For example, if the display covers a week, switch to the following week. With prefix arg, go forward that many times @code{org-agenda-ndays} days. - +@c @kindex @key{left} @item @key{left} Display the previous dates. - +@c @kindex . @item . Goto today. +@tsubheading{Query editing} +@cindex query editing, in agenda + +@kindex [ +@kindex ] +@kindex @{ +@kindex @} +@item [ ] @{ @} +In the @i{search view} (@pxref{Keyword search}), these keys add new +search words (@kbd{[} and @kbd{]}) or new regular expressions (@kbd{@{} +and @kbd{@}}) to the query string. The opening bracket/brace will add a +positive search term prefixed by @samp{+}, indicating that this search +term @i{must} occur/match in the entry. Closing bracket/brace add a +negative search term which @i{must not} occur/match in the entry for it +to be selected. + + @tsubheading{Remote editing} @cindex remote editing, from agenda @item 0-9 Digit argument. - +@c @cindex undoing remote-editing events @cindex remote editing, undo @kindex C-_ @item C-_ Undo a change due to a remote editing command. The change is undone both in the agenda buffer and in the remote buffer. - +@c @kindex t @item t Change the TODO state of the item, both in the agenda and in the original org file. - +@c @kindex C-k @item C-k Delete the current agenda item along with the entire subtree belonging to it in the original Org-mode file. If the text to be deleted remotely is longer than one line, the kill needs to be confirmed by the user. See variable @code{org-agenda-confirm-kill}. - +@c @kindex $ @item $ Archive the subtree corresponding to the current headline. - +@c @kindex T @item T Show all tags associated with the current item. Because of inheritance, this may be more than the tags listed in the line itself. - +@c @kindex : @item : -Set tags for the current headline. - +Set tags for the current headline. If there is an active region in the +agenda, change a tag for all headings in the region. +@c @kindex a @item a Toggle the ARCHIVE tag for the current headline. - +@c @kindex , @item , Set the priority for the current item. Org-mode prompts for the priority character. If you reply with @key{SPC}, the priority cookie is removed from the entry. - +@c @kindex P @item P Display weighted priority of current item. - +@c @kindex + @kindex S-@key{up} @item + @@ -4178,21 +5570,21 @@ Display weighted priority of current item. Increase the priority of the current item. The priority is changed in the original buffer, but the agenda is not resorted. Use the @kbd{r} key for this. - +@c @kindex - @kindex S-@key{down} @item - @itemx S-@key{down} Decrease the priority of the current item. - +@c @kindex C-c C-s @item C-c C-s Schedule this item - +@c @kindex C-c C-d @item C-c C-d Set a deadline for this item. - +@c @kindex S-@key{right} @item S-@key{right} Change the time stamp associated with the current line by one day into @@ -4201,39 +5593,45 @@ example, @kbd{3 6 5 S-@key{right}} will change it by a year. The stamp is changed in the original org file, but the change is not directly reflected in the agenda buffer. Use the @kbd{r} key to update the buffer. - +@c @kindex S-@key{left} @item S-@key{left} Change the time stamp associated with the current line by one day into the past. - +@c @kindex > @item > Change the time stamp associated with the current line to today. The key @kbd{>} has been chosen, because it is the same as @kbd{S-.} on my keyboard. - +@c @kindex I @item I Start the clock on the current item. If a clock is running already, it is stopped first. +@c @kindex O @item O Stop the previously started clock. +@c @kindex X @item X Cancel the currently running clock. +@kindex J +@item J +Jump to the running clock in another window. + @tsubheading{Calendar commands} @cindex calendar commands, from agenda @kindex c @item c Open the Emacs calendar and move to the date at the agenda cursor. - +@c @item c When in the calendar, compute and show the Org-mode agenda for the date at the cursor. - +@c @cindex diary entries, creating from agenda @kindex i @item i @@ -4241,42 +5639,53 @@ Insert a new entry into the diary. Prompts for the type of entry (day, weekly, monthly, yearly, anniversary, cyclic) and creates a new entry in the diary, just as @kbd{i d} etc. would do in the calendar. The date is taken from the cursor position. - +@c @kindex M @item M Show the phases of the moon for the three months around current date. - +@c @kindex S @item S Show sunrise and sunset times. The geographical location must be set with calendar variables, see documentation of the Emacs calendar. - +@c @kindex C @item C Convert the date at cursor into many other cultural and historic calendars. - +@c @kindex H @item H Show holidays for three month around the cursor date. - +@c @c FIXME: This should be a different key. @kindex C-c C-x C-c @item C-c C-x C-c Export a single iCalendar file containing entries from all agenda files. +@tsubheading{Exporting to a file} +@kindex C-x C-w +@item C-x C-w +@cindex exporting agenda views +@cindex agenda views, exporting +Write the agenda view to a file. Depending on the extension of the +selected file name, the view will be exported as HTML (extension +@file{.html} or @file{.htm}), Postscript (extension @file{.ps}), or +plain text (any other extension). Use the variable +@code{org-agenda-exporter-settings} to set options for @file{ps-print} +and for @file{htmlize} to be used during export. + @tsubheading{Quit and Exit} @kindex q @item q Quit agenda, remove the agenda buffer. - +@c @kindex x @cindex agenda files, removing buffers @item x Exit agenda, remove the agenda buffer and all buffers loaded by Emacs for the compilation of the agenda. Buffers created by the user to visit org files will not be removed. - @end table @@ -4294,7 +5703,8 @@ dispatcher (@pxref{Agenda dispatcher}), just like the default commands. * Storing searches:: Type once, use often * Block agenda:: All the stuff you need in a single buffer * Setting Options:: Changing the rules -* Batch processing:: Agenda views from the command line +* Exporting Agenda Views:: Writing agendas to files. +* Extracting Agenda Information for other programs:: @end menu @node Storing searches, Block agenda, Custom agenda views, Custom agenda views @@ -4316,19 +5726,28 @@ search types: (setq org-agenda-custom-commands '(("w" todo "WAITING") ("W" todo-tree "WAITING") - ("u" tags "+BOSS-URGENT") - ("v" tags-todo "+BOSS-URGENT") - ("U" tags-tree "+BOSS-URGENT") - ("f" occur-tree "\\"))) + ("u" tags "+boss-urgent") + ("v" tags-todo "+boss-urgent") + ("U" tags-tree "+boss-urgent") + ("f" occur-tree "\\") + ("h" . "HOME+Name tags searches") ; description for "h" prefix + ("hl" tags "+home+Lisa") + ("hp" tags "+home+Peter") + ("hk" tags "+home+Kim"))) @end group @end lisp @noindent -The initial single-character string in each entry defines the character -you have to press after the dispatcher command @kbd{C-c a} in order to -access the command. The second parameter is the search type, followed -by the string or regular expression to be used for the matching. The -example above will therefore define: +The initial string in each entry defines the keys you have to press +after the dispatcher command @kbd{C-c a} in order to access the command. +Usually this will be just a single character, but if you have many +similar commands, you can also define two-letter combinations where the +first character is the same in several combinations and serves as a +prefix key@footnote{You can provide a description for a prefix key by +inserting a cons cell with the prefix and the description.}. The second +parameter is the search type, followed by the string or regular +expression to be used for the matching. The example above will +therefore define: @table @kbd @item C-c a w @@ -4338,8 +5757,8 @@ keyword as the same search, but only in the current buffer and displaying the results as a sparse tree @item C-c a u -as a global tags search for headlines marked @samp{:BOSS:} but not -@samp{:URGENT:} +as a global tags search for headlines marked @samp{:boss:} but not +@samp{:urgent:} @item C-c a v as the same search as @kbd{C-c a u}, but limiting the search to headlines that are also TODO items @@ -4348,7 +5767,11 @@ as the same search as @kbd{C-c a u}, but only in the current buffer and displaying the result as a sparse tree @item C-c a f to create a sparse tree (again: current buffer only) with all entries -containing the word @samp{FIXME}. +containing the word @samp{FIXME} +@item C-c a h +as a prefix command for a HOME tags search where you have to press an +additional key (@kbd{l}, @kbd{p} or @kbd{k}) to select a name (Lisa, +Peter, or Kim) as additional tag to match. @end table @node Block agenda, Setting Options, Storing searches, Custom agenda views @@ -4368,13 +5791,13 @@ matching commands discussed above: @code{todo}, @code{tags}, and @group (setq org-agenda-custom-commands '(("h" "Agenda and Home-related tasks" - ((agenda) - (tags-todo "HOME") - (tags "GARDEN"))) + ((agenda "") + (tags-todo "home") + (tags "garden"))) ("o" "Agenda and Office-related tasks" - ((agenda) - (tags-todo "WORK") - (tags "OFFICE"))))) + ((agenda "") + (tags-todo "work") + (tags "office"))))) @end group @end lisp @@ -4382,11 +5805,10 @@ matching commands discussed above: @code{todo}, @code{tags}, and This will define @kbd{C-c a h} to create a multi-block view for stuff you need to attend to at home. The resulting agenda buffer will contain your agenda for the current week, all TODO items that carry the tag -@samp{HOME}, and also all lines tagged with @samp{GARDEN}. Finally the +@samp{home}, and also all lines tagged with @samp{garden}. Finally the command @kbd{C-c a o} provides a similar view for office tasks. - -@node Setting Options, Batch processing, Block agenda, Custom agenda views +@node Setting Options, Exporting Agenda Views, Block agenda, Custom agenda views @subsection Setting Options for custom commands @cindex options, for custom agenda views @@ -4403,19 +5825,23 @@ right spot in @code{org-agenda-custom-commands}. For example: '(("w" todo "WAITING" ((org-agenda-sorting-strategy '(priority-down)) (org-agenda-prefix-format " Mixed: "))) - ("U" tags-tree "+BOSS-URGENT" + ("U" tags-tree "+boss-urgent" ((org-show-following-heading nil) - (org-show-hierarchy-above nil))))) + (org-show-hierarchy-above nil))) + ("N" search "" + ((org-agenda-files '("~org/notes.org")) + (org-agenda-text-search-extra-files nil))))) @end group @end lisp @noindent Now the @kbd{C-c a w} command will sort the collected entries only by -priority, and the prefix format is modified to just say @samp{ Mixed:} +priority, and the prefix format is modified to just say @samp{ Mixed: } instead of giving the category of the entry. The sparse tags tree of @kbd{C-c a U} will now turn out ultra-compact, because neither the headline hierarchy above the match, nor the headline following the match -will be shown. +will be shown. The command @kbd{C-c a N} will do a text search limited +to only a single file. For command sets creating a block agenda, @code{org-agenda-custom-commands} has two separate spots for setting @@ -4433,13 +5859,14 @@ the results for GARDEN tags query in the opposite order, (setq org-agenda-custom-commands '(("h" "Agenda and Home-related tasks" ((agenda) - (tags-todo "HOME") - (tags "GARDEN" ((org-agenda-sorting-strategy '(priority-up))))) + (tags-todo "home") + (tags "garden" + ((org-agenda-sorting-strategy '(priority-up))))) ((org-agenda-sorting-strategy '(priority-down)))) ("o" "Agenda and Office-related tasks" ((agenda) - (tags-todo "WORK") - (tags "OFFICE"))))) + (tags-todo "work") + (tags "office"))))) @end group @end lisp @@ -4450,36 +5877,241 @@ this interface, the @emph{values} are just lisp expressions. So if the value is a string, you need to add the double quotes around the value yourself. -@node Batch processing, , Setting Options, Custom agenda views -@subsection Creating agenda views in batch processing -@cindex agenda, batch production -If you want to print or otherwise reprocess agenda views, it can be -useful to create an agenda from the command line. This is the purpose -of the function @code{org-batch-agenda}. It takes as a parameter one of -the strings that are the keys in @code{org-agenda-custom-commands}. For -example, to directly print the current TODO list, you could use +@node Exporting Agenda Views, Extracting Agenda Information for other programs, Setting Options, Custom agenda views +@subsection Exporting Agenda Views +@cindex agenda views, exporting + +If you are away from your computer, it can be very useful to have a +printed version of some agenda views to carry around. Org-mode can +export custom agenda views as plain text, HTML@footnote{You need to +install Hrvoje Niksic' @file{htmlize.el}.} postscript, and iCalendar +files. If you want to do this only occasionally, use the command + +@table @kbd +@kindex C-x C-w +@item C-x C-w +@cindex exporting agenda views +@cindex agenda views, exporting +Write the agenda view to a file. Depending on the extension of the +selected file name, the view will be exported as HTML (extension +@file{.html} or @file{.htm}), Postscript (extension @file{.ps}), +iCalendar (extension @file{.ics}), or plain text (any other extension). +Use the variable @code{org-agenda-exporter-settings} to +set options for @file{ps-print} and for @file{htmlize} to be used during +export, for example + +@lisp +(setq org-agenda-exporter-settings + '((ps-number-of-columns 2) + (ps-landscape-mode t) + (htmlize-output-type 'css))) +@end lisp +@end table + +If you need to export certain agenda views frequently, you can associate +any custom agenda command with a list of output file names +@footnote{If you want to store standard views like the weekly agenda +or the global TODO list as well, you need to define custom commands for +them in order to be able to specify file names.}. Here is an example +that first does define custom commands for the agenda and the global +todo list, together with a number of files to which to export them. +Then we define two block agenda commands and specify file names for them +as well. File names can be relative to the current working directory, +or absolute. + +@lisp +@group +(setq org-agenda-custom-commands + '(("X" agenda "" nil ("agenda.html" "agenda.ps")) + ("Y" alltodo "" nil ("todo.html" "todo.txt" "todo.ps")) + ("h" "Agenda and Home-related tasks" + ((agenda "") + (tags-todo "home") + (tags "garden")) + nil + ("~/views/home.html")) + ("o" "Agenda and Office-related tasks" + ((agenda) + (tags-todo "work") + (tags "office")) + nil + ("~/views/office.ps" "~/calendars/office.ics")))) +@end group +@end lisp + +The extension of the file name determines the type of export. If it is +@file{.html}, Org-mode will use the @file{htmlize.el} package to convert +the buffer to HTML and save it to this file name. If the extension is +@file{.ps}, @code{ps-print-buffer-with-faces} is used to produce +postscript output. If the extension is @file{.ics}, iCalendar export is +run export over all files that were used to construct the agenda, and +limit the export to entries listed in the agenda now. Any other +extension produces a plain ASCII file. + +The export files are @emph{not} created when you use one of those +commands interactively because this might use too much overhead. +Instead, there is a special command to produce @emph{all} specified +files in one step: + +@table @kbd +@kindex C-c a e +@item C-c a e +Export all agenda views that have export file names associated with +them. +@end table + +You can use the options section of the custom agenda commands to also +set options for the export commands. For example: + +@lisp +(setq org-agenda-custom-commands + '(("X" agenda "" + ((ps-number-of-columns 2) + (ps-landscape-mode t) + (org-agenda-prefix-format " [ ] ") + (org-agenda-with-colors nil) + (org-agenda-remove-tags t)) + ("theagenda.ps")))) +@end lisp + +@noindent +This command sets two options for the postscript exporter, to make it +print in two columns in landscape format - the resulting page can be cut +in two and then used in a paper agenda. The remaining settings modify +the agenda prefix to omit category and scheduling information, and +instead include a checkbox to check off items. We also remove the tags +to make the lines compact, and we don't want to use colors for the +black-and-white printer. Settings specified in +@code{org-agenda-exporter-settings} will also apply, but the settings +in @code{org-agenda-custom-commands} take precedence. + +@noindent +From the command line you may also use +@example +emacs -f org-batch-store-agenda-views -kill +@end example +@noindent +or, if you need to modify some parameters +@example +emacs -eval '(org-batch-store-agenda-views \ + org-agenda-ndays 30 \ + org-agenda-start-day "2007-11-01" \ + org-agenda-include-diary nil \ + org-agenda-files (quote ("~/org/project.org")))' \ + -kill +@end example +@noindent +which will create the agenda views restricted to the file +@file{~/org/project.org}, without diary entries and with 30 days +extent. + +@node Extracting Agenda Information for other programs, , Exporting Agenda Views, Custom agenda views +@subsection Extracting Agenda Information for other programs +@cindex agenda, pipe +@cindex Scripts, for agenda processing + +Org-mode provides commands to access agenda information for the command +line in emacs batch mode. This extracted information can be sent +directly to a printer, or it can be read by a program that does further +processing of the data. The first of these commands is the function +@code{org-batch-agenda}, that produces an agenda view and sends it as +ASCII text to STDOUT. The command takes a single string as parameter. +If the string has length 1, it is used as a key to one of the commands +you have configured in @code{org-agenda-custom-commands}, basically any +key you can use after @kbd{C-c a}. For example, to directly print the +current TODO list, you could use @example emacs -batch -l ~/.emacs -eval '(org-batch-agenda "t")' | lpr @end example +If the parameter is a string with 2 or more characters, it is used as a +tags/todo match string. For example, to print your local shopping list +(all items with the tag @samp{shop}, but excluding the tag +@samp{NewYork}), you could use + +@example +emacs -batch -l ~/.emacs \ + -eval '(org-batch-agenda "+shop-NewYork")' | lpr +@end example + @noindent You may also modify parameters on the fly like this: @example emacs -batch -l ~/.emacs \ -eval '(org-batch-agenda "a" \ - org-agenda-ndays 300 \ + org-agenda-ndays 30 \ org-agenda-include-diary nil \ org-agenda-files (quote ("~/org/project.org")))' \ | lpr @end example @noindent -which will produce a 300 day agenda, fully restricted to the Org file +which will produce a 30 day agenda, fully restricted to the Org file @file{~/org/projects.org}, not even including the diary. +If you want to process the agenda data in more sophisticated ways, you +can use the command @code{org-batch-agenda-csv} to get a comma-separated +list of values for each agenda item. Each line in the output will +contain a number of fields separated by commas. The fields in a line +are: + +@example +category @r{The category of the item} +head @r{The headline, without TODO kwd, TAGS and PRIORITY} +type @r{The type of the agenda entry, can be} + todo @r{selected in TODO match} + tagsmatch @r{selected in tags match} + diary @r{imported from diary} + deadline @r{a deadline} + scheduled @r{scheduled} + timestamp @r{appointment, selected by timestamp} + closed @r{entry was closed on date} + upcoming-deadline @r{warning about nearing deadline} + past-scheduled @r{forwarded scheduled item} + block @r{entry has date block including date} +todo @r{The todo keyword, if any} +tags @r{All tags including inherited ones, separated by colons} +date @r{The relevant date, like 2007-2-14} +time @r{The time, like 15:00-16:50} +extra @r{String with extra planning info} +priority-l @r{The priority letter if any was given} +priority-n @r{The computed numerical priority} +@end example + +@noindent +Time and date will only be given if a timestamp (or deadline/scheduled) +lead to the selection of the item. + +A CSV list like this is very easy to use in a post processing script. +For example, here is a Perl program that gets the TODO list from +Emacs/org-mode and prints all the items, preceded by a checkbox: + +@example +@group +#!/usr/bin/perl + +# define the Emacs command to run +$cmd = "emacs -batch -l ~/.emacs -eval '(org-batch-agenda-csv \"t\")'"; + +# run it and capture the output +$agenda = qx@{$cmd 2>/dev/null@}; + +# loop over all lines +foreach $line (split(/\n/,$agenda)) @{ + + # get the individual values + ($category,$head,$type,$todo,$tags,$date,$time,$extra, + $priority_l,$priority_n) = split(/,/,$line); + + # proccess and print + print "[ ] $head\n"; +@} +@end group +@end example + @node Embedded LaTeX, Exporting, Agenda views, Top @chapter Embedded LaTeX @cindex @TeX{} interpretation @@ -4557,19 +6189,23 @@ are surrounded with @code{} and @code{} tags, respectively. With symbols, sub- and superscripts, HTML is pretty much at its end when it comes to representing mathematical formulas@footnote{Yes, there is MathML, but that is not yet fully supported by many browsers, and there -is no decent converter for turning LaTeX of ASCII representations of -formulas into MathML. So for the time being, converting formulas into -images seems the way to go.}. More complex -expressions need a dedicated formula processor. To this end, Org-mode -can contain arbitrary La@TeX{} fragments. It provides commands to -preview the typeset result of these fragments, and upon export to HTML, -all fragments will be converted to images and inlined into the HTML -document. For this to work you need to be on a system with a working -La@TeX{} installation. You also need the @file{dvipng} program, -available at @url{http://sourceforge.net/projects/dvipng/}. +is no decent converter for turning La@TeX{} or ASCII representations of +formulas into MathML. So for the time being, converting formulas into +images seems the way to go.}. More complex expressions need a dedicated +formula processor. To this end, Org-mode can contain arbitrary La@TeX{} +fragments. It provides commands to preview the typeset result of these +fragments, and upon export to HTML, all fragments will be converted to +images and inlined into the HTML document@footnote{The La@TeX{} export +will not use images for displaying La@TeX{} fragments but include these +fragments directly into the La@TeX{} code.}. For this to work you +need to be on a system with a working La@TeX{} installation. You also +need the @file{dvipng} program, available at +@url{http://sourceforge.net/projects/dvipng/}. The La@TeX{} header that +will be used when processing a fragment can be configured with the +variable @code{org-format-latex-header}. La@TeX{} fragments don't need any special marking at all. The following -snippets will be identified as LaTeX source code: +snippets will be identified as La@TeX{} source code: @itemize @bullet @item Environments of any kind. The only requirement is that the @@ -4635,7 +6271,7 @@ setting is active: @cindex CDLaTeX CDLaTeX-mode is a minor mode that is normally used in combination with a -major LaTeX mode like AUCTeX in order to speed-up insertion of +major La@TeX{} mode like AUCTeX in order to speed-up insertion of environments and math templates. Inside Org-mode, you can make use of some of the features of cdlatex-mode. You need to install @file{cdlatex.el} and @file{texmathp.el} (the latter comes also with @@ -4658,7 +6294,7 @@ Environment templates can be inserted with @kbd{C-c @{}. @item @kindex @key{TAB} The @key{TAB} key will do template expansion if the cursor is inside a -LaTeX fragment@footnote{Org-mode has a method to test if the cursor is +La@TeX{} fragment@footnote{Org-mode has a method to test if the cursor is inside such a fragment, see the documentation of the function @code{org-inside-LaTeX-fragment-p}.}. For example, @key{TAB} will expand @code{fr} to @code{\frac@{@}@{@}} and position the cursor @@ -4671,7 +6307,7 @@ To get a list of all abbreviations, type @kbd{M-x cdlatex-command-help}. @item @kindex _ @kindex ^ -Pressing @kbd{_} and @kbd{^} inside a LaTeX fragment will insert these +Pressing @kbd{_} and @kbd{^} inside a La@TeX{} fragment will insert these characters together with a pair of braces. If you use @key{TAB} to move out of the braces, and if the braces surround only a single character or macro, they are removed again (depending on the variable @@ -4679,7 +6315,7 @@ macro, they are removed again (depending on the variable @item @kindex ` Pressing the backquote @kbd{`} followed by a character inserts math -macros, also outside LaTeX fragments. If you wait more than 1.5 seconds +macros, also outside La@TeX{} fragments. If you wait more than 1.5 seconds after the backquote, a help window will pop up. @item @kindex ' @@ -4698,11 +6334,12 @@ Org-mode documents can be exported into a variety of other formats. For printing and sharing of notes, ASCII export produces a readable and simple version of an Org-mode file. HTML export allows you to publish a notes file on the web, while the XOXO format provides a solid base for -exchange with a broad range of other applications. To incorporate -entries with associated times like deadlines or appointments into a -desktop calendar program like iCal, Org-mode can also produce extracts -in the iCalendar format. Currently Org-mode only supports export, not -import of these different formats. +exchange with a broad range of other applications. La@TeX{} export lets +you use Org-mode and its structured editing functions to easily create +La@TeX{} files. To incorporate entries with associated times like +deadlines or appointments into a desktop calendar program like iCal, +Org-mode can also produce extracts in the iCalendar format. Currently +Org-mode only supports export, not import of these different formats. When exporting, Org-mode uses special conventions to enrich the output produced. @xref{Text interpretation}, for more details. @@ -4718,6 +6355,7 @@ command. @menu * ASCII export:: Exporting to plain ASCII * HTML export:: Exporting to HTML +* LaTeX export:: Exporting to LaTeX * XOXO export:: Exporting to XOXO * iCalendar export:: Exporting in iCalendar format * Text interpretation:: How the exporter looks at the file @@ -4736,10 +6374,13 @@ file. @table @kbd @kindex C-c C-e a @item C-c C-e a -Export as ASCII file. If there is an active region, only the region -will be exported. For an org file @file{myfile.org}, the ASCII file +Export as ASCII file. For an org file @file{myfile.org}, the ASCII file will be @file{myfile.txt}. The file will be overwritten without -warning. +warning. If there is an active region, only the region will be +exported. If the selected region is a single tree, the tree head will +become the document title. If the tree head entry has or inherits an +@code{:EXPORT_FILE_NAME:} property, that name will be used for the +export. @kindex C-c C-e v a @item C-c C-e v a Export only the visible part of the document. @@ -4764,7 +6405,7 @@ the body text. Any indentation larger than this is adjusted to preserve the layout relative to the first line. Should there be lines with less indentation than the first, these are left alone. -@node HTML export, XOXO export, ASCII export, Exporting +@node HTML export, LaTeX export, ASCII export, Exporting @section HTML export @cindex HTML export @@ -4773,14 +6414,14 @@ HTML formatting, in ways similar to John Grubers @emph{markdown} language, but with additional support for tables. @menu -* Export commands:: How to invode HTML export +* HTML Export commands:: How to invoke LaTeX export * Quoting HTML tags:: Using direct HTML in Org-mode -* Links:: How hyperlinks get transferred to HTML -* Images:: To inline or not to inline? -* CSS support:: Style specifications +* Links:: Transformation of links for HTML +* Images:: How to include images +* CSS support:: Changing the appearence of the output @end menu -@node Export commands, Quoting HTML tags, HTML export, HTML export +@node HTML Export commands, Quoting HTML tags, HTML export, HTML export @subsection HTML export commands @cindex region, active @@ -4789,15 +6430,40 @@ language, but with additional support for tables. @table @kbd @kindex C-c C-e h @item C-c C-e h -Export as HTML file @file{myfile.html}. +Export as HTML file @file{myfile.html}. For an org file +@file{myfile.org}, the ASCII file will be @file{myfile.html}. The file +will be overwritten without warning. If there is an active region, only +the region will be exported. If the selected region is a single tree, +the tree head will become the document title. If the tree head entry +has or inherits an @code{:EXPORT_FILE_NAME:} property, that name will be +used for the export. @kindex C-c C-e b @item C-c C-e b -Export as HTML file and open it with a browser. +Export as HTML file and immediately open it with a browser. +@kindex C-c C-e H +@item C-c C-e H +Export to a temporary buffer, do not create a file. +@kindex C-c C-e R +@item C-c C-e R +Export the active region to a temporary buffer. With prefix arg, do not +produce file header and foot, but just the plain HTML section for the +region. This is good for cut-and-paste operations. @kindex C-c C-e v h @kindex C-c C-e v b +@kindex C-c C-e v H +@kindex C-c C-e v R @item C-c C-e v h @item C-c C-e v b +@item C-c C-e v H +@item C-c C-e v R Export only the visible part of the document. +@item M-x org-export-region-as-html +Convert the region to HTML under the assumption that it was org-mode +syntax before. This is a global command that can be invoked in any +buffer. +@item M-x org-replace-region-by-HTML +Replace the active region (assumed to be in Org-mode syntax) by HTML +code. @end table @cindex headline levels, for exporting @@ -4813,7 +6479,7 @@ at a different level, specify it with a prefix argument. For example, @noindent creates two levels of headings and does the rest as items. -@node Quoting HTML tags, Links, Export commands, HTML export +@node Quoting HTML tags, Links, HTML Export commands, HTML export @subsection Quoting HTML tags Plain @samp{<} and @samp{>} are always transformed to @samp{<} and @@ -4917,7 +6583,96 @@ section in the buffer. @c FIXME: More about header and footer styles @c FIXME: Talk about links and targets. -@node XOXO export, iCalendar export, HTML export, Exporting +@node LaTeX export, XOXO export, HTML export, Exporting +@section LaTeX export +@cindex LaTeX export + +Org-mode contains a La@TeX{} exporter written by Bastien Guerry. + +@menu +* LaTeX export commands:: How to invoke LaTeX export +* Quoting LaTeX code:: Incorporating literal LaTeX code +* Sectioning structure:: +@end menu + +@node LaTeX export commands, Quoting LaTeX code, LaTeX export, LaTeX export +@subsection LaTeX export commands + +@table @kbd +@kindex C-c C-e l +@item C-c C-e l +Export as La@TeX{} file @file{myfile.tex}. +@kindex C-c C-e L +@item C-c C-e L +Export to a temporary buffer, do not create a file. +@kindex C-c C-e v l +@kindex C-c C-e v L +@item C-c C-e v l +@item C-c C-e v L +Export only the visible part of the document. +@item M-x org-export-region-as-latex +Convert the region to La@TeX{} under the assumption that it was org-mode +syntax before. This is a global command that can be invoked in any +buffer. +@item M-x org-replace-region-by-latex +Replace the active region (assumed to be in Org-mode syntax) by La@TeX{} +code. +@end table + +@cindex headline levels, for exporting +In the exported version, the first 3 outline levels will become +headlines, defining a general document structure. Additional levels +will be exported as description lists. The exporter can ignore them or +convert them to a custom string depending on +@code{org-latex-low-levels}. + +If you want that transition to occur at a different level, specify it +with a prefix argument. For example, + +@example +@kbd{C-2 C-c C-e l} +@end example + +@noindent +creates two levels of headings and does the rest as items. + +@node Quoting LaTeX code, Sectioning structure, LaTeX export commands, LaTeX export +@subsection Quoting LaTeX code + +Embedded La@TeX{} as described in @ref{Embedded LaTeX} will be correctly +inserted into the La@TeX{} file. Forthermore, you can add special code +that should only be present in La@TeX{} export with the following +constructs: + +@example +#+LaTeX: Literal LaTeX code for export +@end example + +@noindent or + +@example +#+BEGIN_LaTeX +All lines between these markers are exported literally +#+END_LaTeX +@end example + + + +@node Sectioning structure, , Quoting LaTeX code, LaTeX export +@subsection Sectioning structure +@cindex LaTeX class +@cindex LaTeX sectioning structure + +By default, the La@TeX{} output uses the class @code{article}. + +You can change this globally by setting a different value for +@code{org-export-latex-default-class} or locally by adding an option +like @code{#+LaTeX_CLASS: myclass} in your file. The class should be +listed in @code{org-export-latex-classes}, where you can also define the +sectioning structure for each class. + + +@node XOXO export, iCalendar export, LaTeX export, Exporting @section XOXO export @cindex XOXO export @@ -4963,6 +6718,11 @@ Create a single large iCalendar file from all files in @code{org-combined-agenda-icalendar-file}. @end table +The export will honor SUMMARY, DESCRIPTION and LOCATION properties if +the selected entries have them. If not, the summary will be derived +from the headline, and the description from the body (limited to +@code{org-icalendar-include-body} characters). + How this calendar is best read and updated, depends on the application you are using. The FAQ covers this issue. @@ -4975,19 +6735,21 @@ in order to produce better output. @menu * Comment lines:: Some lines will not be exported +* Initial text:: Text before the first headline +* Footnotes:: Numbers like [1] +* Quoted examples:: Inserting quoted chnuks of text * Enhancing text:: Subscripts, symbols and more * Export options:: How to influence the export settings @end menu -@node Comment lines, Enhancing text, Text interpretation, Text interpretation +@node Comment lines, Initial text, Text interpretation, Text interpretation @subsection Comment lines @cindex comment lines @cindex exporting, not Lines starting with @samp{#} in column zero are treated as comments and will never be exported. Also entire subtrees starting with the -word @samp{COMMENT} will never be exported. Finally, any text before -the first headline will not be exported either. +word @samp{COMMENT} will never be exported. @table @kbd @kindex C-c ; @@ -4995,15 +6757,112 @@ the first headline will not be exported either. Toggle the COMMENT keyword at the beginning of an entry. @end table -@node Enhancing text, Export options, Comment lines, Text interpretation +@node Initial text, Footnotes, Comment lines, Text interpretation +@subsection Text before the first headline + +Org-mode normally ignores any text before the first headline when +exporting, leaving this region for internal links to speed up navigation +etc. However, in publishing-oriented files, you might want to have some +text before the first headline, like a small introduction, special HTML +code with a navigation bar, etc. You can ask to have this part of the +file exported as well by setting the variable +@code{org-export-skip-text-before-1st-heading} to @code{nil}. On a +per-file basis, you can get the same effect with + +@example +#+OPTIONS: skip:nil +@end example + +The text before the first headline will be fully processed +(@pxref{Enhancing text}), and the first non-comment line becomes the +title of the exported document. If you need to include literal HTML, +use the special constructs described in @ref{Quoting HTML tags}. The +table of contents is normally inserted directly before the first +headline of the file. If you would like to get it to a different +location, insert the string @code{[TABLE-OF-CONTENTS]} on a line by +itself at the desired location. + +Finally, if you want to use the space before the first headline for +internal purposes, but @emph{still} want to place something before the +first headline when exporting the file, you can use the @code{#+TEXT} +construct: + +@example +#+OPTIONS: skip:t +#+TEXT: This text will go before the *first* headline. +#+TEXT: We place the table of contents here: +#+TEXT: [TABLE-OF-CONTENTS] +#+TEXT: This goes between the table of contents and the first headline +@end example + +@node Footnotes, Quoted examples, Initial text, Text interpretation +@subsection Footnotes +@cindex footnotes +@cindex @file{footnote.el} + +Numbers in square brackets are treated as footnotes, so that you can use +the Emacs package @file{footnote.el} to create footnotes. For example: + +@example +The org-mode homepage[1] clearly needs help from +a good web designer. + +[1] The link is: http://orgmode.org +@end example + +@noindent +@kindex C-c ! +Note that the @file{footnote} package uses @kbd{C-c !} to invoke its +commands. This binding conflicts with the org-mode command for +inserting inactive time stamps. You could use the variable +@code{footnote-prefix} to switch footnotes commands to another key. Or, +if you are too used to this binding, you could use +@code{org-replace-disputed-keys} and @code{org-disputed-keys} to change +the settings in Org-mode. + +@node Quoted examples, Enhancing text, Footnotes, Text interpretation +@subsection Quoted examples +@cindex quoted examples +@cindex examples, quoted +@cindex text, fixed width +@cindex fixed width text + +When writing technical documents, you often need to insert examples that +are not further interpreted by Org-mode. For historical reasons, there +are several ways to do this: + +@itemize @bullet +@item +If a headline starts with the word @samp{QUOTE}, the text below the +headline will be typeset as fixed-width, to allow quoting of computer +codes etc. +@item +Lines starting with @samp{:} are also typeset in fixed-width font. +@table @kbd +@kindex C-c : +@item C-c : +Toggle fixed-width for entry (QUOTE) or region, see below. +@end table +@item +Finally, text between +@example +#+BEGIN_EXAMPLE +quoted text +#+END_EXAMPLE +@end example +will also be exported in this way. +@end itemize + + +@node Enhancing text, Export options, Quoted examples, Text interpretation @subsection Enhancing text for export @cindex enhancing text @cindex richer text Some of the export backends of Org-mode allow for sophisticated text -formatting, this is true in particular for the HTML backend. Org-mode -has a number of typing conventions that allow to produce a richly -formatted output. +formatting, this is true in particular for the HTML and La@TeX{} +backends. Org-mode has a number of typing conventions that allow to +produce a richly formatted output. @itemize @bullet @@ -5017,9 +6876,12 @@ backend supports lists. See @xref{Plain lists}. @cindex underlined text @cindex bold text @cindex italic text +@cindex verbatim text @item -You can make words @b{*bold*}, @i{/italic/}, _underlined_, -@code{=code=}, and @samp{+strikethrough+}. +You can make words @b{*bold*}, @i{/italic/}, _underlined_, @code{=code=} +and @code{~verbatim~}, and, if you must, @samp{+strikethrough+}. Text +in the code and verbatim string is not processed for org-mode specific +syntax, it is exported verbatim. @cindex horizontal rules, in exported files @item @@ -5042,22 +6904,38 @@ separator line will be formatted as table header fields. @item If a headline starts with the word @samp{QUOTE}, the text below the headline will be typeset as fixed-width, to allow quoting of computer -codes etc. Lines starting with @samp{:} are also typeset in -fixed-width font. +codes etc. Lines starting with @samp{:} are also typeset in fixed-width +font. @table @kbd @kindex C-c : @item C-c : Toggle fixed-width for entry (QUOTE) or region, see below. @end table +Finally, text between +@example +#+BEGIN_EXAMPLE +quoted text +#+END_EXAMPLE +@end example +will also be exported in this way. @cindex linebreak, forced -@item +@item A double backslash @emph{at the end of a line} enforces a line break at this position. + +@cindex HTML entities, LaTeX entities +@item +Strings like @code{\alpha} will be exported as @code{α}, in the +HTML output. These strings are exported as @code{$\alpha$} in the +La@TeX{} output. Similarly, @code{\nbsp} will become @code{ } in +HTML and in La@TeX{}. This applies for a long list of entities, see +the variable @code{org-html-entities} for the complete list. +@c FIXME @end itemize If these conversions conflict with your habits of typing ASCII text, -they can all be turned off with corresponding variables (see the +they can all be turned off with corresponding variables. See the customization group @code{org-export-general}, and the following section which explains how to set export options with special lines in a buffer. @@ -5084,11 +6962,12 @@ Insert template with export options, see example below. @example #+TITLE: the title to be shown (default is the buffer name) #+AUTHOR: the author (default taken from @code{user-full-name}) +#+DATE: A date, fixed, of a format string for @code{format-time-string} #+EMAIL: his/her email address (default from @code{user-mail-address}) #+LANGUAGE: language for HTML, e.g. @samp{en} (@code{org-export-default-language}) #+TEXT: Some descriptive text to be inserted at the beginning. #+TEXT: Several lines may be given. -#+OPTIONS: H:2 num:t toc:t \n:nil @@:t ::t |:t ^:t *:nil TeX:t LaTeX:t +#+OPTIONS: H:2 num:t toc:t \n:nil @@:t ::t |:t ^:t f:t TeX:t ... @end example @noindent @@ -5102,37 +6981,57 @@ you can: @cindex fixed-width sections @cindex tables @cindex @TeX{}-like syntax for sub- and superscripts +@cindex footnotes +@cindex special strings @cindex emphasized text @cindex @TeX{} macros @cindex La@TeX{} fragments +@cindex author info, in export +@cindex time info, in export @example -H: @r{set the number of headline levels for export} -num: @r{turn on/off section-numbers} -toc: @r{turn on/off table of contents, or set level limit (integer)} -\n: @r{turn on/off linebreak-preservation} -@@: @r{turn on/off quoted HTML tags} -:: @r{turn on/off fixed-width sections} -|: @r{turn on/off tables} -^: @r{turn on/off @TeX{}-like syntax for sub- and superscripts.} -*: @r{turn on/off emphasized text (bold, italic, underlined)} -TeX: @r{turn on/off simple @TeX{} macros in plain text} -LaTeX: @r{turn on/off La@TeX{} fragments} +H: @r{set the number of headline levels for export} +num: @r{turn on/off section-numbers} +toc: @r{turn on/off table of contents, or set level limit (integer)} +\n: @r{turn on/off linebreak-preservation} +@@: @r{turn on/off quoted HTML tags} +:: @r{turn on/off fixed-width sections} +|: @r{turn on/off tables} +^: @r{turn on/off @TeX{}-like syntax for sub- and superscripts. If} + @r{you write "^:@{@}", @code{a_@{b@}} will be interpreted, but} + @r{the simple @code{a_b} will be left as it is.} +-: @r{turn on/off conversion of special strings.} +f: @r{turn on/off foototes like this[1].} +*: @r{turn on/off emphasized text (bold, italic, underlined)} +TeX: @r{turn on/off simple @TeX{} macros in plain text} +LaTeX: @r{turn on/off La@TeX{} fragments} +skip: @r{turn on/off skipping the text before the first heading} +author: @r{turn on/off inclusion of author name/email into exported file} +timestamp: @r{turn on/off inclusion creation time into exported file} +d: @r{turn on/off inclusion of drawers} @end example +These options take effect in both the HTML and La@TeX{} export, except +for @code{TeX} and @code{LaTeX}, which are respectively @code{t} and +@code{nil} for the La@TeX{} export. + @node Publishing, Miscellaneous, Exporting, Top @chapter Publishing @cindex publishing -Org-mode includes@footnote{@file{org-publish.el} is not yet part of -Emacs, so if you are using @file{org.el} as it comes with Emacs, you -need to download this file separately. Also make sure org.el is at -least version 4.27.} a publishing management system -that allows you to configure automatic HTML conversion of -@emph{projects} composed of interlinked org files. This system is -called @emph{org-publish}. You can also configure org-publish to -automatically upload your exported HTML pages and related attachments, -such as images and source code files, to a web server. Org-publish turns -org-mode into a web-site authoring tool. +Org-mode includes@footnote{@file{org-publish.el} is not distributed with +Emacs 21, if you are still using Emacs 21, you need you need to download +this file separately.} a publishing management system that allows you to +configure automatic HTML conversion of @emph{projects} composed of +interlinked org files. This system is called @emph{org-publish}. You can +also configure org-publish to automatically upload your exported HTML +pages and related attachments, such as images and source code files, to +a web server. Org-publish turns org-mode into a web-site authoring tool. + +You can also use Org-publish to convert files into La@TeX{}, or even +combine HTML and La@TeX{} conversion so that files are available in both +formats on the server@footnote{Since La@TeX{} files on a server are not +that helpful, you surely want to perform further conversion on them -- +e.g. convert them to @code{PDF} format.}. Org-publish has been contributed to Org-mode by David O'Toole. @@ -5169,11 +7068,11 @@ Each element of the list configures one project, and may be in one of the two following forms: @lisp -("project-name" :property value :property value ...) +("project-name" :property value :property value ...) -@r{or} - -("project-name" :components ("project-name" "project-name" ...)) +@r{or} + +("project-name" :components ("project-name" "project-name" ...)) @end lisp @@ -5211,13 +7110,13 @@ run @code{make} for updating files to be published. By default, all files with extension @file{.org} in the base directory are considered part of the project. This can be modified by setting the -properties +properties @multitable @columnfractions 0.25 0.75 @item @code{:base-extension} @tab Extension (without the dot!) of source files. This actually is a regular expression. -@item @code{:exclude} +@item @code{:exclude} @tab Regular expression to match file names that should not be published, even though they have been selected on the basis of their extension. @@ -5235,9 +7134,11 @@ Publishing means that a file is copied to the destination directory and possibly transformed in the process. The default transformation is to export Org-mode files as HTML files, and this is done by the function @code{org-publish-org-to-html} which calls the HTML exporter -(@pxref{HTML export}). Other files like images only need to be copied -to the publishing destination. For non-Org-mode files, you need to -specify the publishing function. +(@pxref{HTML export}). But you also can publish your files in La@TeX{} by +using the function @code{org-publish-org-to-latex} instead. Other files +like images only need to be copied to the publishing destination. For +non-Org-mode files, you need to specify the publishing function. + @multitable @columnfractions 0.3 0.7 @item @code{:publishing-function} @@ -5254,13 +7155,13 @@ provides one for attachments (files that only need to be copied): @code{org-publish-attachment}. @node Publishing options, Publishing links, Publishing action, Configuration -@subsection Options for the HTML exporter +@subsection Options for the HTML/LaTeX exporters @cindex options, for publishing The property list can be used to set many export options for the HTML -exporter. In most cases, these properties correspond to user variables -in Org-mode. The table below lists these properties along with the -variable they belong to. See the documentation string for the +and La@TeX{} exporters. In most cases, these properties correspond to user +variables in Org-mode. The table below lists these properties along +with the variable they belong to. See the documentation string for the respective variable for details. @multitable @columnfractions 0.3 0.7 @@ -5271,6 +7172,7 @@ respective variable for details. @item @code{:archived-trees} @tab @code{org-export-with-archived-trees} @item @code{:emphasize} @tab @code{org-export-with-emphasize} @item @code{:sub-superscript} @tab @code{org-export-with-sub-superscripts} +@item @code{:special-strings} @tab @code{org-export-with-special-strings} @item @code{:TeX-macros} @tab @code{org-export-with-TeX-macros} @item @code{:LaTeX-fragments} @tab @code{org-export-with-LaTeX-fragments} @item @code{:fixed-width} @tab @code{org-export-with-fixed-width} @@ -5292,9 +7194,16 @@ respective variable for details. @item @code{:email} @tab @code{user-mail-address} @end multitable -When a property is given a value in org-publish-project-alist, its -setting overrides the value of the corresponding user variable (if any) -during publishing. options set within a file (@pxref{Export +If you use several email addresses, separate them by a semi-column. + +Most of the @code{org-export-with-*} variables have the same effect in +both HTML and La@TeX{} exporters, except for @code{:TeX-macros} and +@code{:LaTeX-fragments}, respectively @code{nil} and @code{t} in the +La@TeX{} export. + +When a property is given a value in @code{org-publish-project-alist}, +its setting overrides the value of the corresponding user variable (if +any) during publishing. Options set within a file (@pxref{Export options}), however, override everything. @node Publishing links, Project page index, Publishing options, Configuration @@ -5310,12 +7219,12 @@ you publish them to HTML. You may also link to related files, such as images. Provided you are careful with relative pathnames, and provided you have also configured -org-publish to upload the related files, these links will work +@code{org-publish} to upload the related files, these links will work too. @ref{Complex example} for an example of this usage. Sometime an Org-mode file to be published may contain links that are only valid in your production environment, but not in the publishing -location. In this case, use the property +location. In this case, use the property @multitable @columnfractions 0.4 0.6 @item @code{:link-validation-function} @@ -5376,12 +7285,12 @@ directory on the local machine. @lisp (setq org-publish-project-alist - '(("org" + '(("org" :base-directory "~/org/" :publishing-directory "~/public_html" :section-numbers nil :table-of-contents nil - :style ""))) @end lisp @@ -5418,17 +7327,17 @@ right place on the webserver, and publishing images to it. :headline-levels 3 :section-numbers nil :table-of-contents nil - :style "" :auto-preamble t :auto-postamble nil) - + ("images" :base-directory "~/images/" :base-extension "jpg\\|gif\\|png" :publishing-directory "/ssh:user@@host:~/html/images/" :publishing-function org-publish-attachment) - + ("other" :base-directory "~/other/" :base-extension "css\\|el" @@ -5441,16 +7350,16 @@ right place on the webserver, and publishing images to it. @section Triggering publication Once org-publish is properly configured, you can publish with the -following functions: +following functions: @table @kbd -@item C-c C-e c +@item C-c C-e C Prompt for a specific project and publish all files that belong to it. -@item C-c C-e p +@item C-c C-e P Publish the project containing the current file. -@item C-c C-e f +@item C-c C-e F Publish only the current file. -@item C-c C-e a +@item C-c C-e A Publish all projects. @end table @@ -5479,6 +7388,7 @@ force publishing of all files by giving a prefix argument. @cindex completion, of dictionary words @cindex completion, of option keywords @cindex completion, of tags +@cindex completion, of property keys @cindex completion, of link abbreviations @cindex @TeX{} symbol completion @cindex TODO keywords completion @@ -5504,10 +7414,14 @@ After @samp{\}, complete @TeX{} symbols supported by the exporter. After @samp{*}, complete headlines in the current buffer so that they can be used in search links like @samp{[[*find this headline]]}. @item -After @samp{:}, complete tags. The list of tags is taken from the -variable @code{org-tag-alist} (possibly set through the @samp{#+TAGS} -in-buffer option, @pxref{Setting tags}), or it is created dynamically -from all tags used in the current buffer. +After @samp{:} in a headline, complete tags. The list of tags is taken +from the variable @code{org-tag-alist} (possibly set through the +@samp{#+TAGS} in-buffer option, @pxref{Setting tags}), or it is created +dynamically from all tags used in the current buffer. +@item +After @samp{:} and not in a headline, complete property keys. The list +of keys is constructed dynamically from all keys used in the current +buffer. @item After @samp{[}, complete link abbreviations (@pxref{Link abbreviations}). @item @@ -5553,8 +7467,40 @@ activate the changes immediately. Otherwise they become effective only when the file is visited again in a new Emacs session. @table @kbd +@item #+ARCHIVE: %s_done:: +This line sets the archive location for the agenda file. It applies for +all subsequent lines until the next @samp{#+ARCHIVE} line, or the end +of the file. The first such line also applies to any entries before it. +The corresponding variable is @code{org-archive-location}. +@item #+CATEGORY: +This line sets the category for the agenda file. The category applies +for all subsequent lines until the next @samp{#+CATEGORY} line, or the +end of the file. The first such line also applies to any entries before it. +@item #+COLUMNS: %25ITEM ..... +Set the default format for columns view. This format applies when +columns view is invoked in location where no @code{COLUMNS} property +applies. +@item #+CONSTANTS: name1=value1 ... +Set file-local values for constants to be used in table formulas. This +line set the local variable @code{org-table-formula-constants-local}. +The global version of this variable is +@code{org-table-formula-constants}. +@item #+DRAWERS: NAME1 ..... +Set the file-local set of drawers. The corresponding global variable is +@code{org-drawers}. +@item #+LINK: linkword replace +These lines (several are allowed) specify link abbreviations. +@xref{Link abbreviations}. The corresponding variable is +@code{org-link-abbrev-alist}. +@item #+PRIORITIES: highest lowest default +This line sets the limits and the default for the priorities. All three +must be either letters A-Z or numbers 0-9. The highest priority must +have a lower ASCII number that the lowest priority. +@item #+PROPERTY: Property_Name Value +This line sets a default inheritance value for entries in the current +buffer, most useful for specifying the allowed values of a property. @item #+STARTUP: -This line sets options to be used at startup of org-mode, when an +This line sets options to be used at startup of Org-mode, when an Org-mode file is being visited. The first set of options deals with the initial visibility of the outline tree. The corresponding variable for global default settings is @code{org-startup-folded}, with a default @@ -5570,26 +7516,33 @@ showall @r{no folding at all, show everything} Then there are options for aligning tables upon visiting a file. This is useful in files containing narrowed table columns. The corresponding variable is @code{org-startup-align-all-tables}, with a default value -@code{nil}. +@code{nil}. @cindex @code{align}, STARTUP keyword @cindex @code{noalign}, STARTUP keyword @example align @r{align all tables} noalign @r{don't align tables on startup} @end example -Logging TODO state changes and clock intervals (variable -@code{org-log-done}) can be configured using these options. +Logging closing and reinstating TODO items, and clock intervals +(variables @code{org-log-done}, @code{org-log-note-clock-out}, and +@code{org-log-repeat}) can be configured using these options. @cindex @code{logdone}, STARTUP keyword -@cindex @code{nologging}, STARTUP keyword @cindex @code{lognotedone}, STARTUP keyword +@cindex @code{nologdone}, STARTUP keyword @cindex @code{lognoteclock-out}, STARTUP keyword -@cindex @code{lognotestate}, STARTUP keyword +@cindex @code{nolognoteclock-out}, STARTUP keyword +@cindex @code{logrepeat}, STARTUP keyword +@cindex @code{lognoterepeat}, STARTUP keyword +@cindex @code{nologrepeat}, STARTUP keyword @example -logging @r{record a timestamp when an item is marked DONE} -nologging @r{don't record when items are marked DONE} -lognotedone @r{record timestamp and a note when DONE} -lognotestate @r{record timestamp, note when TODO state changes} -lognoteclock-out @r{record timestamp and a note when clocking out} +logdone @r{record a timestamp when an item is marked DONE} +lognotedone @r{record timestamp and a note when DONE} +nologdone @r{don't record when items are marked DONE} +logrepeat @r{record a time when reinstating a repeating item} +lognoterepeat @r{record a note when reinstating a repeating item} +nologrepeat @r{do not record when reinstating repeating item} +lognoteclock-out @r{record a note when clocking out} +nolognoteclock-out @r{don't record a note when clocking out} @end example Here are the options for hiding leading stars in outline headings. The corresponding variables are @code{org-hide-leading-stars} and @@ -5612,32 +7565,27 @@ To turn on custom format overlays over time stamps (variables @example customtime @r{overlay custom time format} @end example -@item #+SEQ_TODO: #+TYP_TODO: -These lines set the TODO keywords and their interpretation in the -current file. The corresponding variables are @code{org-todo-keywords} -and @code{org-todo-interpretation}. +The following options influence the table spreadsheet (variable +@code{constants-unit-system}). +@cindex @code{constcgs}, STARTUP keyword +@cindex @code{constSI}, STARTUP keyword +@example +constcgs @r{@file{constants.el} should use the c-g-s unit system} +constSI @r{@file{constants.el} should use the SI unit system} +@end example @item #+TAGS: TAG1(c1) TAG2(c2) These lines (several such lines are allowed) specify the valid tags in this file, and (potentially) the corresponding @emph{fast tag selection} keys. The corresponding variable is @code{org-tag-alist}. -@item #+LINK: linkword replace -These lines (several are allowed) specify link abbreviations. -@xref{Link abbreviations}. The corresponding variable is -@code{org-link-abbrev-alist}. -@item #+CATEGORY: -This line sets the category for the agenda file. The category applies -for all subsequent lines until the next @samp{#+CATEGORY} line, or the -end of the file. The first such line also applies to any entries before it. -@item #+ARCHIVE: %s_done:: -This line sets the archive location for the agenda file. It applies for -all subsequent lines until the next @samp{#+CATEGORY} line, or the end -of the file. The first such line also applies to any entries before it. -The corresponding variable is @code{org-archive-location}. @item #+TBLFM: This line contains the formulas for the table directly above the line. -@item #+TITLE:, #+AUTHOR:, #+EMAIL:, #+LANGUAGE:, #+TEXT:, #+OPTIONS: +@item #+TITLE:, #+AUTHOR:, #+EMAIL:, #+LANGUAGE:, #+TEXT:, #+OPTIONS, #+DATE: These lines provide settings for exporting files. For more details see @ref{Export options}. +@item #+SEQ_TODO: #+TYP_TODO: +These lines set the TODO keywords and their interpretation in the +current file. The corresponding variables are @code{org-todo-keywords} +and @code{org-todo-interpretation}. @end table @node The very busy C-c C-c key, Clean view, In-buffer settings, Miscellaneous @@ -5659,7 +7607,7 @@ tree, or from clock display, remove these highlights. @item If the cursor is in one of the special @code{#+KEYWORD} lines, this triggers scanning the buffer for these lines and updating the -information. +information. @item If the cursor is inside a table, realign the table. This command works even if the automatic table editor has been turned off. @@ -5677,11 +7625,17 @@ default location. If the cursor is on a @code{<<>>}, update radio targets and corresponding links in this buffer. @item +If the cursor is in a property line or at the start or end of a property +drawer, offer property commands. +@item If the cursor is in a plain list item with a checkbox, toggle the status of the checkbox. @item If the cursor is on a numbered item in a plain list, renumber the ordered list. +@item +If the cursor is on the @code{#+BEGIN} line of a dynamical block, the +block is updated. @end itemize @node Clean view, TTY keys, The very busy C-c C-c key, Miscellaneous @@ -5789,18 +7743,17 @@ org-convert-to-oddeven-levels}. @section Using org-mode on a tty @cindex tty keybindings -Org-mode uses a number of keys that are not accessible on a tty. This -applies to most special keys like cursor keys, @key{TAB} and -@key{RET}, when these are combined with modifier keys like @key{Meta} -and/or @key{Shift}. Org-mode uses these bindings because it needs to -provide keys for a large number of commands, and because these keys -appeared particularly easy to remember. In order to still be able to -access the core functionality of Org-mode on a tty, alternative -bindings are provided. Here is a complete list of these bindings, -which are obviously more cumbersome to use. Note that sometimes a -work-around can be better. For example changing a time stamp is -really only fun with @kbd{S-@key{cursor}} keys. On a tty you would -rather use @kbd{C-c .} to re-insert the timestamp. +Because Org-mode contains a large number of commands, by default much of +Org-mode's core commands are bound to keys that are generally not +accessible on a tty, such as the cursor keys (@key{left}, @key{right}, +@key{up}, @key{down}), @key{TAB} and @key{RET}, in particular when used +together with modifiers like @key{Meta} and/or @key{Shift}. To access +these commands on a tty when special keys are unavailable, the following +alternative bindings can be used. The tty bindings below will likely be +more cumbersome; you may find for some of the bindings below that a +customized work-around suits you better. For example, changing a time +stamp is really only fun with @kbd{S-@key{cursor}} keys, whereas on a +tty you would rather use @kbd{C-c .} to re-insert the timestamp. @multitable @columnfractions 0.15 0.2 0.2 @item @b{Default} @tab @b{Alternative 1} @tab @b{Alternative 2} @@ -5816,10 +7769,12 @@ rather use @kbd{C-c .} to re-insert the timestamp. @item @kbd{S-@key{RET}} @tab @kbd{C-c C-x c} @tab @item @kbd{M-@key{RET}} @tab @kbd{C-c C-x m} @tab @kbd{@key{Esc} @key{RET}} @item @kbd{M-S-@key{RET}} @tab @kbd{C-c C-x M} @tab -@item @kbd{S-@key{left}} @tab @kbd{C-c C-x @key{left}} @tab -@item @kbd{S-@key{right}} @tab @kbd{C-c C-x @key{right}} @tab -@item @kbd{S-@key{up}} @tab @kbd{C-c C-x @key{up}} @tab -@item @kbd{S-@key{down}} @tab @kbd{C-c C-x @key{down}} @tab +@item @kbd{S-@key{left}} @tab @kbd{C-c @key{left}} @tab +@item @kbd{S-@key{right}} @tab @kbd{C-c @key{right}} @tab +@item @kbd{S-@key{up}} @tab @kbd{C-c @key{up}} @tab +@item @kbd{S-@key{down}} @tab @kbd{C-c @key{down}} @tab +@item @kbd{C-S-@key{left}} @tab @kbd{C-c C-x @key{left}} @tab +@item @kbd{C-S-@key{right}} @tab @kbd{C-c C-x @key{right}} @tab @end multitable @node Interaction, Bugs, TTY keys, Miscellaneous @@ -5863,10 +7818,27 @@ setup. See the installation instructions in the file @cindex @file{cdlatex.el} Org-mode can make use of the cdlatex package to efficiently enter La@TeX{} fragments into Org-mode files. See @ref{CDLaTeX mode}. +@item @file{imenu.el} by Ake Stenhoff and Lars Lindberg +@cindex @file{imenu.el} +Imenu allows menu access to an index of items in a file. Org-mode +supports imenu - all you need to do to get the index is the following: +@lisp +(add-hook 'org-mode-hook + (lambda () 'imenu-add-to-menubar "Imenu")) +@end lisp +By default the index is two levels deep - you can modify the depth using +the option @code{org-imenu-depth}. @item @file{remember.el} by John Wiegley @cindex @file{remember.el} Org mode cooperates with remember, see @ref{Remember}. @file{Remember.el} is not part of Emacs, find it on the web. +@item @file{speedbar.el} by Eric M. Ludlam +@cindex @file{speedbar.el} +Speedbar is a package that creates a special frame displaying files and +index items in files. Org-mode supports speedbar and allows you to +drill into Org-mode files directly from the speedbar. It also allows to +restrict the scope of agenda commands to a file or a subtree by using +the command @kbd{<} in the speedbar frame. @cindex @file{table.el} @item @file{table.el} by Takaaki Ota @kindex C-c C-c @@ -5887,7 +7859,7 @@ to execute Org-mode-related commands, leave the table. @item C-c C-c Recognize @file{table.el} table. Works when the cursor is in a table.el table. - +@c @kindex C-c ~ @item C-c ~ Insert a table.el table. If there is already a table at point, this @@ -5897,6 +7869,10 @@ format. See the documentation string of the command possible. @end table @file{table.el} is part of Emacs 22. +@cindex @file{footnote.el} +@item @file{footnote.el} by Steven L. Baur +Org-mode recognizes numerical footnotes as provided by this package +(@pxref{Footnotes}). @end table @node Conflicts, , Cooperation, Interaction @@ -5916,18 +7892,16 @@ is loaded @emph{before} @file{allout.el}, for example by putting @cindex @file{CUA.el} @item @file{CUA.el} by Kim. F. Storm -Keybindings in Org-mode conflict with the @kbd{S-} keys -used by CUA-mode (as well as pc-select-mode and s-region-mode) to -select and extend the region. If you want to use one of these -packages along with Org-mode, configure the variable -@code{org-CUA-compatible}. When set, Org-mode will move the following -keybindings in org-mode files, and in the agenda buffer (but not -during date selection). +Keybindings in Org-mode conflict with the @kbd{S-} keys used by +CUA-mode (as well as pc-select-mode and s-region-mode) to select and +extend the region. If you want to use one of these packages along with +Org-mode, configure the variable @code{org-replace-disputed-keys}. When +set, Org-mode will move the following keybindings in Org-mode files, and +in the agenda buffer (but not during date selection). @example S-UP -> M-p S-DOWN -> M-n S-LEFT -> M-- S-RIGHT -> M-+ -S-RET -> C-S-RET @end example Yes, these are unfortunately more difficult to remember. If you want @@ -5937,6 +7911,16 @@ to have other replacement keys, look at the variable @cindex @file{windmove.el} Also this package uses the @kbd{S-} keys, so everything written in the paragraph above about CUA mode also applies here. + +@cindex @file{footnote.el} +@item @file{footnote.el} by Steven L. Baur +Org-mode supports the syntax of the footnote package, but only the +numerical footnote markers. Also, the default key for footnote +commands, @kbd{C-c !} is already used by Org-mode. You could use the +variable @code{footnote-prefix} to switch footnotes commands to another +key. Or, you could use @code{org-replace-disputed-keys} and +@code{org-disputed-keys} to change the settings in Org-mode. + @end table @@ -5987,12 +7971,14 @@ Org-mode. @menu * Extensions:: Existing 3rd-part extensions +* Adding hyperlink types:: New custom link types * Tables in arbitrary syntax:: Orgtbl for LaTeX and other programs * Dynamic blocks:: Automatically filled blocks * Special agenda views:: Customized views +* Using the property API:: Writing programs that use entry properties @end menu -@node Extensions, Tables in arbitrary syntax, Extensions and Hacking, Extensions and Hacking +@node Extensions, Adding hyperlink types, Extensions and Hacking, Extensions and Hacking @section Third-party extensions for Org-mode @cindex extension, third-party @@ -6032,20 +8018,126 @@ blogs. @url{http://www.cognition.ens.fr/~guerry/blorg.html}. @item @file{org2rem.el} by Bastien Guerry Translates Org-mode files into something readable by Remind. @url{http://www.cognition.ens.fr/~guerry/u/org2rem.el}. +@item @file{org-toc.el} by Bastien Guerry +Produces a simple table of contents of an Org-mode file, for easy +navigation. @url{http://www.cognition.ens.fr/~guerry/u/org-registry.el}. +@item @file{org-registry.el} by Bastien Guerry +Find which Org-file link to a certain document. +@url{http://www.cognition.ens.fr/~guerry/u/org2rem.el}. @end table @page -@node Tables in arbitrary syntax, Dynamic blocks, Extensions, Extensions and Hacking -@section Tables in arbitrary syntax +@node Adding hyperlink types, Tables in arbitrary syntax, Extensions, Extensions and Hacking +@section Adding hyperlink types +@cindex hyperlinks, adding new types + +Org-mode has a large number of hyperlink types built-in +(@pxref{Hyperlinks}). If you would like to add new link types, it +provides an interface for doing so. Lets look at an example file +@file{org-man.el} that will add support for creating links like +@samp{[[man:printf][The printf manpage]]} to show unix manual pages inside +emacs: + +@lisp +;;; org-man.el - Support for links to manpages in Org-mode + +(require 'org) + +(org-add-link-type "man" 'org-man-open) +(add-hook 'org-store-link-functions 'org-man-store-link) + +(defcustom org-man-command 'man + "The Emacs command to be used to display a man page." + :group 'org-link + :type '(choice (const man) (const woman))) + +(defun org-man-open (path) + "Visit the manpage on PATH. +PATH should be a topic that can be thrown at the man command." + (funcall org-man-command path)) + +(defun org-man-store-link () + "Store a link to a manpage." + (when (memq major-mode '(Man-mode woman-mode)) + ;; This is a man page, we do make this link + (let* ((page (org-man-get-page-name)) + (link (concat "man:" page)) + (description (format "Manpage for %s" page))) + (org-store-link-props + :type "man" + :link link + :description description)))) + +(defun org-man-get-page-name () + "Extract the page name from the buffer name." + ;; This works for both `Man-mode' and `woman-mode'. + (if (string-match " \\(\\S-+\\)\\*" (buffer-name)) + (match-string 1 (buffer-name)) + (error "Cannot create link to this man page"))) + +(provide 'org-man) + +;;; org-man.el ends here +@end lisp + +@noindent +You would activate this new link type in @file{.emacs} with + +@lisp +(require 'org-man) +@end lisp + +@noindent +Lets go through the file and see what it does. +@enumerate +@item +It does @code{(require 'org)} to make sure that @file{org.el} has been +loaded. +@item +The next line calls @code{org-add-link-type} to define a new link type +with prefix @samp{man}. The call also contains the name of a function +that will be called to follow such a link. +@item +The next line adds a function to @code{org-store-link-functions}, in +order to allow the command @kbd{C-c l} to record a useful link in a +buffer displaying a man page. +@end enumerate + +The rest of the file defines the necessary variables and functions. +First there is a customization variable that determines which emacs +command should be used to display manpages. There are two options, +@code{man} and @code{woman}. Then the function to follow a link is +defined. It gets the link path as an argument - in this case the link +path is just a topic for the manual command. The function calls the +value of @code{org-man-command} to display the man page. + +Finally the function @code{org-man-store-link} is defined. When you try +to store a link with @kbd{C-c l}, also this function will be called to +try to make a link. The function must first decide if it is supposed to +create the link for this buffer type, we do this by checking the value +of the variable @code{major-mode}. If not, the function must exit and +retunr the value @code{nil}. If yes, the link is created by getting the +manual tpoic from the buffer name and prefixing it with the string +@samp{man:}. Then it must call the command @code{org-store-link-props} +and set the @code{:type} and @code{:link} properties. Optionally you +can also set the @code{:description} property to provide a default for +the link description when the link is later inserted into tan Org-mode +buffer with @kbd{C-c C-l}. + +@node Tables in arbitrary syntax, Dynamic blocks, Adding hyperlink types, Extensions and Hacking +@section Tables and Lists in arbitrary syntax @cindex tables, in other modes +@cindex lists, in other modes @cindex orgtbl-mode Since Orgtbl-mode can be used as a minor mode in arbitrary buffers, a frequent feature request has been to make it work with native tables in -specific languages, for example LaTeX. However, this is extremely hard -to do in a general way, would lead to a customization nightmare, and -would take away much of the simplicity of the Orgtbl-mode table editor. +specific languages, for example La@TeX{}. However, this is extremely +hard to do in a general way, would lead to a customization nightmare, +and would take away much of the simplicity of the Orgtbl-mode table +editor. + This appendix describes a different approach. We keep the Orgtbl-mode table in its native format (the @i{source table}), and use a custom @@ -6054,10 +8146,17 @@ function to @i{translate} the table to the correct syntax, and to the burden of writing conversion functions on the user, but it allows for a very flexible system. +Bastien added the ability to do the same with lists. You can use Org's +facilities to edit and structure lists by turning @code{orgstruct-mode} +on, then locally exporting such lists in another format (HTML, La@TeX{} +or TeXInfo.) + + @menu * Radio tables:: Sending and receiving * A LaTeX example:: Step by step, almost a tutorial * Translator functions:: Copy and modify +* Radio lists:: Doing the same for lists. @end menu @node Radio tables, A LaTeX example, Tables in arbitrary syntax, Tables in arbitrary syntax @@ -6105,7 +8204,7 @@ additional columns. @noindent The one problem remaining is how to keep the source table in the buffer without disturbing the normal workings of the file, for example during -compilation of a C file or processing of a LaTeX file. There are a +compilation of a C file or processing of a La@TeX{} file. There are a number of different solutions: @itemize @bullet @@ -6113,10 +8212,10 @@ number of different solutions: The table could be placed in a block comment if that is supported by the language. For example, in C-mode you could wrap the table between @samp{/*} and @samp{*/} lines. -@item +@item Sometimes it is possible to put the table after some kind of @i{END} statement, for example @samp{\bye} in TeX and @samp{\end@{document@}} -in LaTeX. +in La@TeX{}. @item You can just comment the table line by line whenever you want to process the file, and uncomment it whenever you need to edit the table. This @@ -6126,14 +8225,14 @@ key. @end itemize @node A LaTeX example, Translator functions, Radio tables, Tables in arbitrary syntax -@subsection A LaTeX example +@subsection A LaTeX example of radio tables @cindex LaTeX, and orgtbl-mode -The best way to wrap the source table in LaTeX is to use the +The best way to wrap the source table in La@TeX{} is to use the @code{comment} environment provided by @file{comment.sty}. It has to be activated by placing @code{\usepackage@{comment@}} into the document header. Orgtbl-mode can insert a radio table skeleton@footnote{By -default this works only for LaTeX, HTML, and TeXInfo. Configure the +default this works only for La@TeX{}, HTML, and TeXInfo. Configure the variable @code{orgtbl-radio-tables} to install templates for other modes.} with the command @kbd{M-x orgtbl-insert-radio-table}. You will be prompted for a table name, lets say we use @samp{salesfigures}. You @@ -6150,7 +8249,7 @@ will then get the following template: @noindent The @code{#+ORGTBL: SEND} line tells orgtbl-mode to use the function -@code{orgtbl-to-latex} to convert the table into LaTeX and to put it +@code{orgtbl-to-latex} to convert the table into La@TeX{} and to put it into the receiver location with name @code{salesfigures}. You may now fill in the table, feel free to use the spreadsheet features@footnote{If the @samp{#+TBLFM} line contains an odd number of dollar characters, @@ -6204,7 +8303,7 @@ Month & \multicolumn@{1@}@{c@}@{Days@} & Nr.\ sold & per day\\ \end@{comment@} @end example -The LaTeX translator function @code{orgtbl-to-latex} is already part of +The La@TeX{} translator function @code{orgtbl-to-latex} is already part of Orgtbl-mode. It uses a @code{tabular} environment to typeset the table and marks horizontal lines with @code{\hline}. Furthermore, it interprets the following parameters: @@ -6230,7 +8329,7 @@ may also be a property list with column numbers and formats, for example applied. @end table -@node Translator functions, , A LaTeX example, Tables in arbitrary syntax +@node Translator functions, Radio lists, A LaTeX example, Tables in arbitrary syntax @subsection Translator functions @cindex HTML, and orgtbl-mode @cindex translator function @@ -6265,7 +8364,7 @@ As you can see, the properties passed into the function (variable @var{PARAMS}) are combined with the ones newly defined in the function (variable @var{PARAMS2}). The ones passed into the function (i.e. the ones set by the @samp{ORGTBL SEND} line) take precedence. So if you -would like to use the LaTeX translator, but wanted the line endings to +would like to use the La@TeX{} translator, but wanted the line endings to be @samp{\\[2mm]} instead of the default @samp{\\}, you could just overrule the default with @@ -6274,7 +8373,7 @@ overrule the default with @end example For a new language, you can either write your own converter function in -analogy with the LaTeX translator, or you can use the generic function +analogy with the La@TeX{} translator, or you can use the generic function directly. For example, if you have a language where a table is started with @samp{!BTBL!}, ended with @samp{!ETBL!}, and where table lines are started with @samp{!BL!}, ended with @samp{!EL!} and where the field @@ -6303,6 +8402,49 @@ containing the formatted table. If you write a generally useful translator, please post it on @code{emacs-orgmode@@gnu.org} so that others can benefit from your work. +@node Radio lists, , Translator functions, Tables in arbitrary syntax +@subsection Radio lists +@cindex radio lists +@cindex org-list-insert-radio-list + +Sending and receiving radio lists works exactly the same way than +sending and receiving radio tables (@pxref{Radio tables}) @footnote{You +need to load the @code{org-export-latex.el} package to use radio lists +since the relevant code is there for now.}. As for radio tables, you +can insert radio lists templates in HTML, La@TeX{} and TeXInfo modes by +calling @code{org-list-insert-radio-list}. + +Here are the differences with radio tables: + +@itemize @minus +@item +Use @code{ORGLST} instead of @code{ORGTBL}. +@item +The available translation functions for radio lists don't take +parameters. +@item +`C-c C-c' will work when pressed on the first item of the list. +@end itemize + +Here is a La@TeX{} example. Let's say that you have this in your +La@TeX{} file: + +@example +% BEGIN RECEIVE ORGLST to-buy +% END RECEIVE ORGLST to-buy +\begin@{comment@} +#+ORGLIST: SEND to-buy orgtbl-to-latex +- a new house +- a new computer + + a new keyboard + + a new mouse +- a new life +\end@{comment@} +@end example + +Pressing `C-c C-c' on @code{a new house} and will insert the converted +La@TeX{} list between the two marker lines. + @node Dynamic blocks, Special agenda views, Tables in arbitrary syntax, Extensions and Hacking @section Dynamic blocks @cindex dynamic blocks @@ -6335,8 +8477,11 @@ Update all dynamic blocks in the current file. Updating a dynamic block means to remove all the text between BEGIN and END, parse the BEGIN line for parameters and then call the specific -writer function for this block to insert the new content. For a block -with name @code{myblock}, the writer function is +writer function for this block to insert the new content. If you want +to use the original content in the writer function, you can use the +extra parameter @code{:content}. + +For a block with name @code{myblock}, the writer function is @code{org-dblock-write:myblock} with as only parameter a property list with the parameters given in the begin line. Here is a trivial example of a block that keeps track of when the block update function was last @@ -6363,7 +8508,7 @@ you could add the function @code{org-update-all-dblocks} to a hook, for example @code{before-save-hook}. @code{org-update-all-dblocks} is written in a way that is does nothing in buffers that are not in Org-mode. -@node Special agenda views, , Dynamic blocks, Extensions and Hacking +@node Special agenda views, Using the property API, Dynamic blocks, Extensions and Hacking @section Special Agenda Views @cindex agenda views, user-defined @@ -6389,35 +8534,100 @@ search should continue from there. (defun my-skip-unless-waiting () "Skip trees that are not waiting" (let ((subtree-end (save-excursion (org-end-of-subtree t)))) - (if (re-search-forward ":WAITING:" subtree-end t) + (if (re-search-forward ":waiting:" subtree-end t) nil ; tag found, do not skip subtree-end))) ; tag not found, continue after end of subtree @end lisp -Furthermore you must write a command that uses @code{let} to temporarily -put this function into the variable @code{org-agenda-skip-function}, -sets the header string for the agenda buffer, and calls the todo-list -generator while asking for the specific TODO keyword PROJECT. The -function must also accept one argument MATCH, but it can choose to -ignore it@footnote{MATCH must be present in case you want to define a -custom command for producing this special list. Custom commands always -supply the MATCH argument, but it can be empty if you do not specify it -while defining the command(@pxref{Custom agenda -views}).} (as we do in the example below). Here is the example: +Now you may use this function in an agenda custom command, for example +like this: @lisp -(defun my-org-waiting-projects (&optional match) - "Produce a list of projects that contain a WAITING tag. -MATCH is being ignored." - (interactive) - (let ((org-agenda-skip-function 'my-skip-unless-waiting) - (org-agenda-overriding-header "Projects waiting for something: ")) - ;; make the list - (org-todo-list "PROJECT"))) +(org-add-agenda-custom-command + '("b" todo "PROJECT" + ((org-agenda-skip-function 'my-org-waiting-projects) + (org-agenda-overriding-header "Projects waiting for something: ")))) +@end lisp + +Note that this also binds @code{org-agenda-overriding-header} to get a +meaningful header in the agenda view. + +You may also put a Lisp form into @code{org-agenda-skip-function}. In +particular, you may use the functions @code{org-agenda-skip-entry-if} +and @code{org-agenda-skip-subtree-if} in this form, for example: + +@table @code +@item '(org-agenda-skip-entry-if 'scheduled) +Skip current entry if it has been scheduled. +@item '(org-agenda-skip-entry-if 'notscheduled) +Skip current entry if it has not been scheduled. +@item '(org-agenda-skip-entry-if 'deadline) +Skip current entry if it has a deadline. +@item '(org-agenda-skip-entry-if 'scheduled 'deadline) +Skip current entry if it has a deadline, or if it is scheduled. +@item '(org-agenda-skip-entry 'regexp "regular expression") +Skip current entry if the regular expression matches in the entry. +@item '(org-agenda-skip-entry 'notregexp "regular expression") +Skip current entry unless the regular expression matches. +@item '(org-agenda-skip-subtree-if 'regexp "regular expression") +Same as above, but check and skip the entire subtree. +@end table + +Therefore we could also have written the search for WAITING projects +like this, even without defining a special function: + +@lisp +(org-add-agenda-custom-command + '("b" todo "PROJECT" + ((org-agenda-skip-function '(org-agenda-skip-subtree-if + 'regexp ":waiting:")) + (org-agenda-overriding-header "Projects waiting for something: ")))) @end lisp -@node History and Acknowledgments, GNU Free Documentation License, Extensions and Hacking, Top +@node Using the property API, , Special agenda views, Extensions and Hacking +@section Using the property API +@cindex API, for properties +@cindex properties, API + +Here is a description of the functions that can be used to work with +properties. + +@defun org-entry-properties &optional pom which +Get all properties of the entry at point-or-marker POM. +This includes the TODO keyword, the tags, time strings for deadline, +scheduled, and clocking, and any additional properties defined in the +entry. The return value is an alist, keys may occur multiple times +if the property key was used several times. +POM may also be nil, in which case the current entry is used. +If WHICH is nil or `all', get all properties. If WHICH is +`special' or `standard', only get that subclass. +@end defun +@defun org-entry-get pom property &optional inherit +Get value of PROPERTY for entry at point-or-marker POM. +If INHERIT is non-nil and the entry does not have the property, +then also check higher levels of the hierarchy. This function ignores +the value of @code{org-use-property-inheritance} and requires the +explicit INHERIT flag. +@end defun + +@defun org-entry-delete pom property +Delete the property PROPERTY from entry at point-or-marker POM. +@end defun + +@defun org-entry-put pom property value +Set PROPERTY to VALUE for entry at point-or-marker POM. +@end defun + +@defun org-buffer-property-keys &optional include-specials +Get all property keys in the current buffer. +@end defun + +@defun org-insert-property-drawer +Insert a property drawer at point. +@end defun + +@node History and Acknowledgments, Main Index, Extensions and Hacking, Top @appendix History and Acknowledgments @cindex acknowledgments @cindex history @@ -6440,7 +8650,7 @@ goals that Org-mode still has today: To create a new, outline-based, plain text mode with innovative and intuitive editing features, and to incorporate project planning functionality directly into a notes file. -Since the first release, hundreds of emails to me or on +Since the first release, literally thousands of emails to me or on @code{emacs-orgmode@@gnu.org} have provided a constant stream of bug reports, feedback, new ideas, and sometimes patches and add-on code. Many thanks to everyone who has helped to improve this package. I am @@ -6451,6 +8661,8 @@ let me know. @itemize @bullet +@item +@i{Russel Adams} came up with the idea for drawers. @item @i{Thomas Baumann} contributed the code for links to the MH-E email system. @@ -6469,7 +8681,9 @@ calculations and improved XEmacs compatibility, in particular by porting @item @i{Sacha Chua} suggested to copy some linking code from Planner. @item -@i{Eddward DeVilla} proposed and tested checkbox statistics. +@i{Eddward DeVilla} proposed and tested checkbox statistics. He also +came up with the idea of properties, and that there should be an API for +them. @item @i{Kees Dullemond} used to edit projects lists directly in HTML and so inspired some of the early development, including HTML export. He also @@ -6478,25 +8692,42 @@ asked for a way to narrow wide table columns. @i{Christian Egli} converted the documentation into TeXInfo format, patched CSS formatting into the HTML exporter, and inspired the agenda. @item +@i{David Emery} provided a patch for custom CSS support in exported +HTML agendas. +@item @i{Nic Ferrier} contributed mailcap and XOXO support. @item +@i{Miguel A. Figueroa-Villanueva} implemented hierarchical checkboxes. +@item @i{John Foerch} figured out how to make incremental search show context around a match in a hidden outline tree. @item -@i{Niels Giessen} had the idea to automatically archive DONE trees. +@i{Niels Giesen} had the idea to automatically archive DONE trees. @item -@i{Bastien Guerry} provided extensive feedback and some patches, and -translated David O'Toole's tutorial into French. +@i{Bastien Guerry} wrote the La@TeX{} exporter and has been prolific +with patches, ideas, and bug reports. @item @i{Kai Grossjohann} pointed out key-binding conflicts with other packages. @item -@i{Shidai Liu} (``Leo'') provided extensive feedback and some patches. +@i{Scott Jaderholm} proposed footnotes, control over whitespace between +folded entries, and column view for properties. @item -@i{Leon Liu} asked for embedded LaTeX and tested it. +@i{Shidai Liu} ("Leo") asked for embedded La@TeX{} and tested it. He also +provided frequent feedback and some patches. +@item +@i{Jason F. McBrayer} suggested agenda export to CSV format. +@item +@i{Max Mikhanosha} came up with the idea of refiling. +@item +@i{Dmitri Minaev} sent a patch to set priority limits on a per-file +basis. @item @i{Stefan Monnier} provided a patch to keep the Emacs-Lisp compiler happy. @item +@i{Rick Moynihan} proposed to allow multiple TODO sequences in a file +and to be able to quickly restrict the agenda to a subtree. +@item @i{Todd Neal} provided patches for links to Info files and elisp forms. @item @i{Tim O'Callaghan} suggested in-file links, search options for general @@ -6539,6 +8770,9 @@ subtrees. @item @i{Dale Smith} proposed link abbreviations. @item +@i{Adam Spiers} asked for global linking commands and inspired the link +extension system. support mairix. +@item @i{David O'Toole} wrote @file{org-publish.el} and drafted the manual chapter about publishing. @item @@ -6557,6 +8791,7 @@ really different beasts in their basic ideas and implementation details. I later looked at John's code, however, and learned from his implementation of (i) links where the link itself is hidden and only a description is shown, and (ii) popping up a calendar to select a date. +John has also contributed a number of great ideas directly to Org-mode. @item @i{Carsten Wimmer} suggested some changes and helped fix a bug in linking to GNUS. @@ -6568,17 +8803,13 @@ work on a tty. and contributed various ideas and code snippets. @end itemize -@node GNU Free Documentation License, Index, History and Acknowledgments, Top -@appendix GNU Free Documentation License -@include doclicense.texi - -@node Index, Key Index, GNU Free Documentation License, Top -@unnumbered Index +@node Main Index, Key Index, History and Acknowledgments, Top +@unnumbered The Main Index @printindex cp -@node Key Index, , Index, Top +@node Key Index, , Main Index, Top @unnumbered Key Index @printindex ky @@ -6588,3 +8819,4 @@ and contributed various ideas and code snippets. @ignore arch-tag: 7893d1fe-cc57-4d13-b5e5-f494a1bcc7ac @end ignore +) From 7d562742816b4c550d8c4dd3f31887d5ea757f4e Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Tue, 8 Apr 2008 15:27:49 +0000 Subject: [PATCH 25/56] (c-basic-common-init): Don't set font-lock-extend-after-change-region-function globally. --- lisp/ChangeLog | 104 +++++++++++++++++--------------------- lisp/progmodes/cc-mode.el | 2 +- 2 files changed, 46 insertions(+), 60 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 6ff322cd958..89c3b493858 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2008-04-08 Stefan Monnier + + * progmodes/cc-mode.el (c-basic-common-init): Don't set + font-lock-extend-after-change-region-function globally. + 2008-04-08 Carsten Dominik * textmodes/org-export-latex.el: New file. @@ -121,8 +126,7 @@ (org-remember-templates, org-time-stamp-rounding-minutes) (org-back-over-empty-lines, org-find-base-buffer-visiting) (org-columns-new): Fix typos in docstrings. - (org-ctrl-c-star): Implement a missing branch in the decision - tree. + (org-ctrl-c-star): Implement a missing branch in the decision tree. (org-select-remember-template): Clean the code. (org-prepare-dblock): Add the extra :content parameter. (org-write-agenda): New output type ".ics" files. @@ -130,8 +134,7 @@ time stamps and for TODO entries. (org-export-as-html): Revert the change that killed the html buffer. Side effects first need to be studied carefully. - (org-get-tags-at): Fix the structure of the condition-case - statement. + (org-get-tags-at): Fix the structure of the condition-case statement. (org-ts-regexp0, org-repeat-re, org-display-custom-time) (org-timestamp-change): Fix regulear expressions to swallow the extra character for repeat-shift control. @@ -144,8 +147,8 @@ (org-timestamp-change, org-modify-ts-extra) (org-ts-regexp1): Fix timestamp editing. (org-agenda-custom-commands-local-options): New constant. - (org-agenda-custom-commands): Use - `org-agenda-custom-commands-local-options' to improve customize + (org-agenda-custom-commands): + Use `org-agenda-custom-commands-local-options' to improve customize type. "htmlize": Removed hack to fix face problem with htmlize, it no longer seem necessary. (org-follow-link-hook): New hook. @@ -181,18 +184,15 @@ org-export-html-extension. (org-store-link): Support for links from `rmail-summary-mode'. (org-columns-new, org-complete, org-set-property): Set the - `include-columns' argument in the call to - `org-buffer-property-keys'. + `include-columns' argument in the call to `org-buffer-property-keys'. (org-buffer-property-keys): New argument `include-columns', to include properties expected by any of the COLUMS formats in the current buffer. (org-cleaned-string-for-export): Get rid of drawers first, so that they will be removed also in the text before the first headline. (org-clock-report): Show the clocktable when found. - (org-refile): Fix positioning bug when `org-reverse-note-order' is - nil. - (org-version): With prefix argument, insert `org-version' at - point. + (org-refile): Fix positioning bug when `org-reverse-note-order' is nil. + (org-version): With prefix argument, insert `org-version' at point. (org-agenda-goto): Recenter the window after finding the target location, to make sure the correct position will be displayed. (org-agenda-get-deadlines): Don't scale priority with the warning @@ -202,9 +202,8 @@ be 0. (org-update-checkbox-count): Revamp to deal with hierarchical beckboxes. This was a patch from Miguel A. Figueroa-Villanueva. - (org-schedule, org-deadline): Use - `org-remove-timestamp-with-keyword' to make sure all such time - stamps are removed. + (org-schedule, org-deadline): Use `org-remove-timestamp-with-keyword' + to make sure all such time stamps are removed. (org-mode): Support for `align'. (org-agenda-get-deadlines): Make sure priorities increase as the due date approaches and is passed. @@ -258,8 +257,7 @@ (org-flag-drawer): Use the original value of `outline-regexp'. (org-remember-handler): Add invisible-ok flag to call to `org-end-of-subtree'. - (org-agenda-highlight-todo): Respect - `org-agenda-todo-keyword-format'. + (org-agenda-highlight-todo): Respect `org-agenda-todo-keyword-format'. (org-infile-export-plist): No restriction while searching for options. (org-remember-handler): Remove comments at the end of the buffer. @@ -277,8 +275,7 @@ (org-open-file): Allow multiple %s in command. (org-get-refile-targets): Interpret the new maxlevel setting. (org-refile-targets): New option `:maxlevel'. - (org-copy-subtree): Include empty lines before but not after - subtree. + (org-copy-subtree): Include empty lines before but not after subtree. (org-move-item-down, org-move-item-up): Include empty lines before but not after item. (org-remember-apply-template): Defaults, completions and history @@ -306,12 +303,11 @@ (org-cleaned-string-for-export): Protect verbatim elements. (org-additional-option-like-keywords): Add new keywords. (org-get-entry): Rename from `org-get-cleaned-entry'. - (org-agenda-get-scheduled, org-agenda-get-blocks): Use - `org-agenda-skip-scheduled-if-done'. + (org-agenda-get-scheduled, org-agenda-get-blocks): + Use `org-agenda-skip-scheduled-if-done'. (org-prepare-agenda-buffers): Allow buffers as arguments. (org-entry-properties): Add CATEGORY as a special property. - (org-use-property-inheritance): Allow a list of properties as a - value. + (org-use-property-inheritance): Allow a list of properties as a value. (org-eval-in-calendar): No longer update the prompt. (org-read-date-popup-calendar): Rename from `org-popup-calendar-for-date-prompt'. @@ -361,8 +357,7 @@ (org-version): Change to 5.13e. (org-agenda-file-regexp): Fix typo in docstring. (org-add-planning-info): Fix bug in parenthesis settings. - (org-scan-tags): Catch the case of indirect buffers with no - filename. + (org-scan-tags): Catch the case of indirect buffers with no filename. (org-fast-tag-selection, org-export-as-ascii, org-export-as-html): Re-install switch to mapc, had been removed by accident. (org-columns-map): New binding `C-c C-o'. @@ -380,11 +375,9 @@ (org-todo-blocker-hook, org-todo-trigger-hook): New hooks. (org-remember-apply-template): Catch C-g and make sure window configuration is restored. - (org-agenda-open-link): Make it work with several links in the - line. + (org-agenda-open-link): Make it work with several links in the line. (org-drawers, org-set-regexps-and-options) - (org-get-current-options): Add support for a DRAWERS in-buffer - option. + (org-get-current-options): Add support for a DRAWERS in-buffer option. (org-fit-agenda-window): Use `org-agenda-window-frame-fractions'. (org-agenda-to-appt): Require calendar. (org-entry-get-with-inheritance): Widen for search. @@ -396,8 +389,7 @@ (org-remember-templates): Customization interface improved. (org-export-with-property-drawer): Variable removed. (org-sort-entries): Rewrite using `sort-subr'. - (org-set-property): More appropriate completion during interactive - use. + (org-set-property): More appropriate completion during interactive use. (org-sort-entries): Allow sorting by property. (org-additional-option-like-keywords): Add more values. (org-sort-entries-or-items): Rename from `org-sort-entries'. @@ -436,17 +428,15 @@ `org-agenda-align-tags-to-column'. (org-agenda-align-tags): Allow negative values for `org-agenda-tags-column'. - (org-insert-labeled-timestamps-before-properties-drawer): Remove - var. + (org-insert-labeled-timestamps-before-properties-drawer): Remove var. (org-agenda-to-appt): New optional argument FILTER. (org-complete): Use `org-completion-fallback-command'. (org-find-base-buffer-visiting): Catch the case that there is no buffer visiting the file. (org-todo): Use `org-property-or-variable-value' - (org-prepare-agenda, org-agenda-list): Use - `org-agenda-compact-blocks'. - (org-agenda-schedule, org-agenda-deadline): Call - `org-agenda-show-new-time'. + (org-prepare-agenda, org-agenda-list): Use `org-agenda-compact-blocks'. + (org-agenda-schedule, org-agenda-deadline): + Call `org-agenda-show-new-time'. (org-agenda-show-new-time): New argument PREFIX. (org-colgroup-info-to-vline-list): Fix but that cause a shift in the vertical lines. @@ -469,8 +459,7 @@ (org-set-tags, org-entry-properties): Call `org-get-tags-string' instead of `org-get-tags'. (org-agenda-format-date): Rename from `org-agenda-date-format'. - (org-time-from-absolute, org-agenda-format-date-aligned): New - funs. + (org-time-from-absolute, org-agenda-format-date-aligned): New funs. (org-compatible-face): New argument INHERITS. Inherit from this face if possible. (org-level-1, org-level-2, org-level-3, org-level-4) @@ -491,8 +480,8 @@ `org-occur'. (org-goto): Made into a general lookup command. (org-get-location): Complete rewrite. - (org-goto-ret, org-goto-left, org-goto-right, org-goto-quit): Set - the new variables. + (org-goto-ret, org-goto-left, org-goto-right, org-goto-quit): + Set the new variables. (org-paste-subtree): Whitespace insertion strategy revised. (org-remember-apply-template): Protect v-A from the possibility that v-a might be nil. @@ -535,8 +524,8 @@ (org-fast-tag-selection): Allow setting TODO states through this interface. (org-cycle): Docstring updated. - (org-set-font-lock-defaults, org-agenda-highlight-todo): Use - `org-get-todo-face'. + (org-set-font-lock-defaults, org-agenda-highlight-todo): + Use `org-get-todo-face'. (org-table-edit-field, org-table-show-reference) (org-table-edit-formulas, org-add-log-note) (org-fast-tag-selection, org-agenda, org-prepare-agenda) @@ -544,8 +533,8 @@ `switch-to-buffer-other-window' to make sure that the temporary windows show up on the current frame. (org-mhe-get-message-real-folder, org-batch-store-agenda-views) - (org-get-entries-from-diary, org-replace-region-by-html): Don't - allow pop-up frames. + (org-get-entries-from-diary, org-replace-region-by-html): + Don't allow pop-up frames. (org-agenda-get-deadlines, org-agenda-get-scheduled): Fix problems with time-of-day. (org-agenda-get-scheduled, org-agenda-get-deadlines): Fix problems @@ -578,8 +567,7 @@ (org-store-link): Call the functions in `org-store-link-functions'. (org-activate-tags): Force matches to be in headlines. - (org-batch-store-agenda-views): Fix bug with killing agenda - buffer. + (org-batch-store-agenda-views): Fix bug with killing agenda buffer. (org-columns-display-here): Make sure this works in a narrowed buffer by checking for point-min. (org-columns-display-here): Make the rest of the line intangible, @@ -599,20 +587,18 @@ (org-export-as-ascii, org-export-as-html): Use `inhibit-read-only' instead of `buffer-read-only'. (org-export-as-html): Set `coding-system-for-write'. - (org-archive-subtree): Fixed bug with modifying TODO keyword. + (org-archive-subtree): Fix bug with modifying TODO keyword. (org-beginning-of-line): Also treat C-a special in items. - (org-table-convert-refs-to-rc): Fixed problem with column + (org-table-convert-refs-to-rc): Fix problem with column reference after "..". (org-columns-compute): Don't mark buffer modified because of text properties. (org-batch-store-agenda-views): Use the variable `default-directory', not the function. (org-clock-out-if-current): Respect `org-clock-out-when-done'. - (org-html-entities): Added HTML entities for smileys. - (org-end-of-line): Move to end of line if in headline without - tags. - (org-agenda-day-view, org-agenda-week-view): Remember span as - default. + (org-html-entities): Add HTML entities for smileys. + (org-end-of-line): Move to end of line if in headline without tags. + (org-agenda-day-view, org-agenda-week-view): Remember span as default. (org-columns-edit-value): Rename from `org-column-edit'. (org-columns-display-here-title): Rename from `org-overlay-columns-title'. @@ -649,7 +635,7 @@ (org-preserve-lc): New macro. (org-update-checkbox-count): Catch case when there is no headline. (org-agenda-quit): Remove any column overlays. - (org-beginning-of-item-list): Fixed bug when non-item line is + (org-beginning-of-item-list): Fix bug when non-item line is indented too deep. (org-make-tags-matcher): Handle property matches. (org-table-recalculate): Swap evaluation order: Field formula @@ -660,8 +646,8 @@ 2008-04-06 Chong Yidong - * dired.el (dired-dnd-handle-local-file): Obey - dired-backup-overwrite for copy, move, and link operations. + * dired.el (dired-dnd-handle-local-file): + Obey dired-backup-overwrite for copy, move, and link operations. * dired-aux.el (dired-overwrite-confirmed): Undo last change. @@ -670,8 +656,8 @@ * progmodes/cc-langs.el (c-before-font-lock-function): Correct a typo in the doc string. - * progmodes/cc-mode.el (c-extend-after-change-region): New - function, used in font-lock-extend-after-change-region-function, + * progmodes/cc-mode.el (c-extend-after-change-region): + New function, used in font-lock-extend-after-change-region-function, thus superseding advice on the Font Lock after change functions. 2008-04-06 Chong Yidong diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 36a69acf407..29d3fcad421 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -598,7 +598,7 @@ that requires a literal mode spec at compile time." (add-hook 'before-change-functions 'c-before-change nil t) (make-local-hook 'after-change-functions) (add-hook 'after-change-functions 'c-after-change nil t) - (setq font-lock-extend-after-change-region-function + (set (make-local-variable 'font-lock-extend-after-change-region-function) 'c-extend-after-change-region)) ; Currently (2008-04), only used by AWK. (defun c-setup-doc-comment-style () From fd0a21518d318cfdc122af647536ab0529944262 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Wed, 9 Apr 2008 08:04:22 +0000 Subject: [PATCH 26/56] *** empty log message *** --- lisp/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 89c3b493858..2789f27c64e 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2008-04-09 Alan Mackenzie + + * font-lock.el (font-lock-extend-after-change-region-function): + Make it buffer local. + 2008-04-08 Stefan Monnier * progmodes/cc-mode.el (c-basic-common-init): Don't set From c7ffd3f84e689f53920d88f2c896c15f92bd0645 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Wed, 9 Apr 2008 08:11:58 +0000 Subject: [PATCH 27/56] (font-lock-extend-after-change-region-function): Make it buffer local. --- lisp/font-lock.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/font-lock.el b/lisp/font-lock.el index 33238c275ec..6f010eee19b 100644 --- a/lisp/font-lock.el +++ b/lisp/font-lock.el @@ -998,6 +998,7 @@ and end buffer positions \(in that order) of the region to refontify, or nil \(which directs the caller to fontify a default region). This function should preserve the match-data. The region it returns may start or end in the middle of a line.") +(make-variable-buffer-local 'font-lock-extend-after-change-region-function) (defun font-lock-fontify-buffer () "Fontify the current buffer the way the function `font-lock-mode' would." From 9116dfe6479fd055fa37a2cbe653310ab43cb1b3 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Wed, 9 Apr 2008 20:17:27 +0000 Subject: [PATCH 28/56] * net/tramp.el (tramp-find-file-name-coding-system-alist): New defun. (tramp-handle-insert-file-contents, tramp-handle-write-region): Use it. --- lisp/net/tramp.el | 60 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index d6d6a524be9..aaac6bfda88 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -3888,6 +3888,21 @@ This will break if COMMAND prints a newline, followed by the value of (t (tramp-make-tramp-file-name multi-method method user host ""))))))) +(defun tramp-find-file-name-coding-system-alist (filename tmpname) + "Like `find-operation-coding-system' for Tramp filenames. +Tramp's `insert-file-contents' and `write-region' work over +temporary file names. If `file-coding-system-alist' contains an +expression, which matches more than the file name suffix, the +coding system might not be determined. This function repairs it." + (let (result) + (dolist (elt file-coding-system-alist result) + (when (and (consp elt) (string-match (car elt) filename)) + ;; We found a matching entry in `file-coding-system-alist'. + ;; So we add a similar entry, but with the temporary file name + ;; as regexp. + (add-to-list + 'result (cons (regexp-quote tmpname) (cdr elt)) 'append))))) + (defun tramp-handle-insert-file-contents (filename &optional visit beg end replace) "Like `insert-file-contents' for tramp files." @@ -3916,14 +3931,18 @@ This will break if COMMAND prints a newline, followed by the value of (tramp-message-for-buffer multi-method method user host 9 "Inserting local temp file `%s'..." local-copy) - (setq result (insert-file-contents local-copy nil beg end replace)) - (when visit - (setq buffer-file-name filename) - (set-visited-file-modtime) - (set-buffer-modified-p nil)) - ;; Now `last-coding-system-used' has right value. Remember it. - (when (boundp 'last-coding-system-used) - (setq coding-system-used (symbol-value 'last-coding-system-used))) + ;; We must ensure that `file-coding-system-alist' matches + ;; `local-copy'. + (let ((file-coding-system-alist + (tramp-find-file-name-coding-system-alist filename local-copy))) + (setq result (insert-file-contents local-copy nil beg end replace)) + (when visit + (setq buffer-file-name filename) + (set-visited-file-modtime) + (set-buffer-modified-p nil)) + ;; Now `last-coding-system-used' has right value. Remember it. + (when (boundp 'last-coding-system-used) + (setq coding-system-used (symbol-value 'last-coding-system-used)))) (tramp-message-for-buffer multi-method method user host 9 "Inserting local temp file `%s'...done" local-copy) @@ -4072,17 +4091,20 @@ Returns a file name in `tramp-auto-save-directory' for autosaving this file." ;; Set current buffer. If connection wasn't open, `file-modes' has ;; changed it accidently. (set-buffer curbuf) - ;; We say `no-message' here because we don't want the visited file - ;; modtime data to be clobbered from the temp file. We call - ;; `set-visited-file-modtime' ourselves later on. - (tramp-run-real-handler - 'write-region - (if confirm ; don't pass this arg unless defined for backward compat. - (list start end tmpfil append 'no-message lockname confirm) - (list start end tmpfil append 'no-message lockname))) - ;; Now, `last-coding-system-used' has the right value. Remember it. - (when (boundp 'last-coding-system-used) - (setq coding-system-used (symbol-value 'last-coding-system-used))) + ;; We say `no-message' here because we don't want the visited + ;; file modtime data to be clobbered from the temp file. We + ;; call `set-visited-file-modtime' ourselves later on. We must + ;; ensure that `file-coding-system-alist' matches `tmpfil'. + (let ((file-coding-system-alist + (tramp-find-file-name-coding-system-alist filename tmpfil))) + (tramp-run-real-handler + 'write-region + (if confirm ; don't pass this arg unless defined for backward compat. + (list start end tmpfil append 'no-message lockname confirm) + (list start end tmpfil append 'no-message lockname))) + ;; Now, `last-coding-system-used' has the right value. Remember it. + (when (boundp 'last-coding-system-used) + (setq coding-system-used (symbol-value 'last-coding-system-used)))) ;; The permissions of the temporary file should be set. If ;; filename does not exist (eq modes nil) it has been renamed to ;; the backup file. This case `save-buffer' handles From be3fd538a4ebeb71c15a505c5c05ad6652aa1bb6 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Wed, 9 Apr 2008 20:19:14 +0000 Subject: [PATCH 29/56] * net/trampver.el: Update release number. --- lisp/ChangeLog | 9 +++++++++ lisp/net/trampver.el | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 2789f27c64e..646370529ba 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,12 @@ +2008-04-09 Michael Albinus + + * net/tramp.el (tramp-find-file-name-coding-system-alist): New + defun. + (tramp-handle-insert-file-contents, tramp-handle-write-region): + Use it. + + * net/trampver.el: Update release number. + 2008-04-09 Alan Mackenzie * font-lock.el (font-lock-extend-after-change-region-function): diff --git a/lisp/net/trampver.el b/lisp/net/trampver.el index a6e026f2f21..9d010200372 100644 --- a/lisp/net/trampver.el +++ b/lisp/net/trampver.el @@ -31,7 +31,7 @@ ;; are auto-frobbed from configure.ac, so you should edit that file and run ;; "autoconf && ./configure" to change them. -(defconst tramp-version "2.0.57" +(defconst tramp-version "2.0.58-pre" "This version of Tramp.") (defconst tramp-bug-report-address "tramp-devel@gnu.org" From cadcf6870600c62e53557a5db4d8c90e04ef6dd4 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Wed, 9 Apr 2008 20:29:25 +0000 Subject: [PATCH 30/56] * trampver.texi: Update release number. --- man/ChangeLog | 4 ++++ man/trampver.texi | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/man/ChangeLog b/man/ChangeLog index d2e8838af61..474a2dfdbd3 100644 --- a/man/ChangeLog +++ b/man/ChangeLog @@ -1,3 +1,7 @@ +2008-04-09 Michael Albinus + + * trampver.texi: Update release number. + 2008-04-08 Carsten Dominik * org.texi: Large scale rewrite and changes, moving from version 4.67 diff --git a/man/trampver.texi b/man/trampver.texi index 832f180d0a2..29eae83c815 100644 --- a/man/trampver.texi +++ b/man/trampver.texi @@ -9,7 +9,7 @@ @c In the Tramp CVS, the version number is auto-frobbed from @c configure.ac, so you should edit that file and run @c "autoconf && ./configure" to change the version number. -@set trampver 2.0.57 +@set trampver 2.0.58-pre @c Other flags from configuration @set prefix /usr/local From 65af6499e937fc75c69e42b7af6a3722965a2210 Mon Sep 17 00:00:00 2001 From: Jason Rumney Date: Thu, 10 Apr 2008 09:42:29 +0000 Subject: [PATCH 31/56] New file. --- nt/ChangeLog | 4 ++++ nt/emacsclient.rc | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 nt/emacsclient.rc diff --git a/nt/ChangeLog b/nt/ChangeLog index a7267ce86a4..ae0fe4dedef 100644 --- a/nt/ChangeLog +++ b/nt/ChangeLog @@ -1,3 +1,7 @@ +2008-04-10 Jason Rumney + + * emacsclient.rc: New file. + 2008-03-26 Chong Yidong * Version 22.2 released. diff --git a/nt/emacsclient.rc b/nt/emacsclient.rc new file mode 100644 index 00000000000..48e46630989 --- /dev/null +++ b/nt/emacsclient.rc @@ -0,0 +1,40 @@ +Emacs ICON icons\emacs.ico + +#ifndef VS_VERSION_INFO +#define VS_VERSION_INFO 1 +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 22,2,50,0 + PRODUCTVERSION 22,2,50,0 + FILEFLAGSMASK 0x3FL +#ifdef EMACSDEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "Free Software Foundation\0" + VALUE "FileDescription", "GNU EmacsClient for Windows NT/95/98/2000/ME/XP\0" + VALUE "FileVersion", "22, 2, 50, 0\0" + VALUE "InternalName", "EmacsClient\0" + VALUE "LegalCopyright", "Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008\0" + VALUE "OriginalFilename", "emacsclientw.exe" + VALUE "ProductName", "EmacsClient: Client for the extensible self-documenting text editor\0" + VALUE "ProductVersion", "22, 2, 50, 0\0" + VALUE "OLESelfRegister", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + From 99e0bf597ef0324db24ad1e4c2d28dbceab58b54 Mon Sep 17 00:00:00 2001 From: Jason Rumney Date: Thu, 10 Apr 2008 09:44:59 +0000 Subject: [PATCH 32/56] (CLIENTRES): New variable and build target. (all): Depend on it. ($(TRES)): Use $(TRES) in rule. --- nt/ChangeLog | 4 ++++ nt/makefile.w32-in | 15 ++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/nt/ChangeLog b/nt/ChangeLog index ae0fe4dedef..6aea7bdc112 100644 --- a/nt/ChangeLog +++ b/nt/ChangeLog @@ -2,6 +2,10 @@ * emacsclient.rc: New file. + * makefile.w32-in (CLIENTRES): New variable and build target. + (all): Depend on it. + ($(TRES)): Use $(TRES) in rule. + 2008-03-26 Chong Yidong * Version 22.2 released. diff --git a/nt/makefile.w32-in b/nt/makefile.w32-in index e6567c048f3..aef71cfddd9 100644 --- a/nt/makefile.w32-in +++ b/nt/makefile.w32-in @@ -24,13 +24,15 @@ # FIXME: This file uses DOS EOLs. Convert to Unix after 22.1 is out # (and remove or replace this comment). -ALL = addpm ddeclient runemacs cmdproxy addsection preprep +TRES = $(BLD)/emacs.res +CLIENTRES = $(BLD)/emacsclient.res + +XMFLAGS = + +ALL = addpm ddeclient runemacs cmdproxy addsection preprep $(CLIENTRES) .PHONY: $(ALL) -TRES = $(BLD)/emacs.res - -XMFLAGS = addpm: stamp_BLD $(BLD)/addpm.exe $(BLD)/addpm.exe: $(BLD)/addpm.$(O) @@ -62,7 +64,10 @@ $(BLD)/preprep.exe: $(BLD)/preprep.$(O) # it is not necessary on later versions, it is still ok to use it. # $(TRES): emacs.rc stamp_BLD - $(RC) $(RC_OUT)$(BLD)/emacs.res emacs.rc + $(RC) $(RC_OUT)$(TRES) emacs.rc + +$(CLIENTRES): emacsclient.rc stamp_BLD + $(RC) $(RC_OUT)$(CLIENTRES) emacsclient.rc runemacs: stamp_BLD $(BLD)/runemacs.exe $(BLD)/runemacs.exe: $(BLD)/runemacs.$(O) $(TRES) From 4429f88c1942b0fb05b83ace0df42e56481a66e5 Mon Sep 17 00:00:00 2001 From: Jason Rumney Date: Thu, 10 Apr 2008 09:48:22 +0000 Subject: [PATCH 33/56] (CLIENTRES): New variable and target. (TRES): Remove. ($(BLD)/emacsclientw.exe): Use $(CLIENTRES) instead of $(TRES). --- lib-src/ChangeLog | 6 ++++++ lib-src/makefile.w32-in | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog index c27691a7597..2ed5830d550 100644 --- a/lib-src/ChangeLog +++ b/lib-src/ChangeLog @@ -1,3 +1,9 @@ +2008-04-10 Jason Rumney + + * makefile.w32-in (CLIENTRES): New variable and target. + (TRES): Remove. + ($(BLD)/emacsclientw.exe): Use $(CLIENTRES) instead of $(TRES). + 2008-03-26 Chong Yidong * Version 22.2 released. diff --git a/lib-src/makefile.w32-in b/lib-src/makefile.w32-in index 02f877581c8..e61bbca2a74 100644 --- a/lib-src/makefile.w32-in +++ b/lib-src/makefile.w32-in @@ -75,18 +75,19 @@ ECLIENTOBJS = $(BLD)/emacsclient.$(O) \ $(BLD)/getopt.$(O) \ $(BLD)/getopt1.$(O) \ $(BLD)/ntlib.$(O) -TRES = ../nt/$(BLD)/emacs.res +CLIENTRES = ../nt/$(BLD)/emacsclient.res -$(TRES): ../nt/emacs.rc - $(RC) $(RC_OUT)../nt/$(BLD)/emacs.res $(ALL_DEPS) +$(CLIENTRES): ../nt/emacsclient.rc + @echo Emacsclient resource file must be built from nt directory + @exit -1 $(BLD)/emacsclient.exe: $(ECLIENTOBJS) # put wsock32.lib before $(LIBS) to ensure we don't link to ws2_32.lib $(LINK) $(LINK_OUT)$@ $(LINK_FLAGS) $(ECLIENTOBJS) $(WSOCK32) $(USER32) $(COMCTL32) $(LIBS) -$(BLD)/emacsclientw.exe: $(ECLIENTOBJS) $(TRES) +$(BLD)/emacsclientw.exe: $(ECLIENTOBJS) $(CLIENTRES) # put wsock32.lib before $(LIBS) to ensure we don't link to ws2_32.lib - $(LINK) $(LINK_OUT)$@ $(TRES) -mwindows $(LINK_FLAGS) $(ECLIENTOBJS) $(WSOCK32) $(USER32) $(COMCTL32) $(LIBS) + $(LINK) $(LINK_OUT)$@ $(CLIENTRES) -mwindows $(LINK_FLAGS) $(ECLIENTOBJS) $(WSOCK32) $(USER32) $(COMCTL32) $(LIBS) # emacsclient.$(O) depends on makefile.w32-in because makefile.w32-in # can be edited to define VERSION string, which is part of ECLIENT_CFLAGS. From ac0af1135c279f01e8e20176414b4c9c43e7304c Mon Sep 17 00:00:00 2001 From: Jason Rumney Date: Thu, 10 Apr 2008 10:42:22 +0000 Subject: [PATCH 34/56] (stat): When Vw32_get_true_file_attributes is Qlocal, get attributes only for local files. --- src/w32.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/w32.c b/src/w32.c index e40f9a4b289..bc26d75e78e 100644 --- a/src/w32.c +++ b/src/w32.c @@ -109,6 +109,9 @@ void globals_of_w32 (); extern Lisp_Object Vw32_downcase_file_names; extern Lisp_Object Vw32_generate_fake_inodes; extern Lisp_Object Vw32_get_true_file_attributes; +/* Defined in process.c for its own purpose. */ +extern Lisp_Object Qlocal; + extern int w32_num_mouse_buttons; @@ -2489,6 +2492,8 @@ stat (const char * path, struct stat * buf) } if (!NILP (Vw32_get_true_file_attributes) + && !(EQ (vw32_get_true_file_attributes, Qlocal) && + GetDriveType (name) == DRIVE_FIXED) /* No access rights required to get info. */ && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL)) From 2fa4f0908a61d12a697265793b28fd26cf2e0e9f Mon Sep 17 00:00:00 2001 From: Jason Rumney Date: Thu, 10 Apr 2008 10:42:54 +0000 Subject: [PATCH 35/56] (syms_of_ntproc): Change Vw32_get_true_file attributes default to Qlocal. --- src/w32proc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/w32proc.c b/src/w32proc.c index f050cacf82d..3756f4a8dd1 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -109,6 +109,7 @@ Lisp_Object Vw32_generate_fake_inodes; exactly, at the expense of slower operation. Since true hard links are supported on NTFS volumes, this is only relevant on NT. */ Lisp_Object Vw32_get_true_file_attributes; +extern Lisp_Object Qlocal; Lisp_Object Qhigh, Qlow; @@ -2354,9 +2355,12 @@ the truename of a file can be slow. */); DEFVAR_LISP ("w32-get-true-file-attributes", &Vw32_get_true_file_attributes, doc: /* Non-nil means determine accurate link count in `file-attributes'. -Note that this option is only useful for files on NTFS volumes, where hard links -are supported. Moreover, it slows down `file-attributes' noticeably. */); - Vw32_get_true_file_attributes = Qt; +This option is only useful for files on NTFS volumes, where +hard links are supported. The default value `local' means only do +this for files on local harddrives. Any other non-nil value means do +this even on remote and removable drives where the performance impact +may be noticeable even on modern hardware. */); + Vw32_get_true_file_attributes = Qlocal; staticpro (&Vw32_valid_locale_ids); staticpro (&Vw32_valid_codepages); From bd73563158de9b663c701735c96db760c0ed20c4 Mon Sep 17 00:00:00 2001 From: Jason Rumney Date: Thu, 10 Apr 2008 10:44:51 +0000 Subject: [PATCH 36/56] Fix last change. --- src/ChangeLog | 8 ++++++++ src/w32.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index ea69708e3fe..81379fd1130 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2008-04-10 Jason Rumney + + * w32.c (stat): When Vw32_get_true_file_attributes is Qlocal, get + attributes only for local files. + + * w32proc.c (syms_of_ntproc): Change Vw32_get_true_file attributes + default to Qlocal. + 2008-04-06 YAMAMOTO Mitsuharu * Makefile.in (MAC_OBJ): Add mactoolbox.o. diff --git a/src/w32.c b/src/w32.c index bc26d75e78e..894160a275d 100644 --- a/src/w32.c +++ b/src/w32.c @@ -2492,7 +2492,7 @@ stat (const char * path, struct stat * buf) } if (!NILP (Vw32_get_true_file_attributes) - && !(EQ (vw32_get_true_file_attributes, Qlocal) && + && !(EQ (Vw32_get_true_file_attributes, Qlocal) && GetDriveType (name) == DRIVE_FIXED) /* No access rights required to get info. */ && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, From 474d35ca3f9f6942ddaaee2298e83185a736a688 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Thu, 10 Apr 2008 20:47:59 +0000 Subject: [PATCH 37/56] * fileio.c (Fmake_symbolic_link): Surround code by #ifdef S_IFLNK only after check for file name handler functions. Signal, when native functionality is not supported. (syms_of_fileio): Declare it unconditionally. --- src/ChangeLog | 7 +++++++ src/fileio.c | 11 +++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 81379fd1130..1894f6d99ad 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2008-04-10 Michael Albinus + + * fileio.c (Fmake_symbolic_link): Surround code by #ifdef S_IFLNK + only after check for file name handler functions. Signal, when + native functionality is not supported. + (syms_of_fileio): Declare it unconditionally. + 2008-04-10 Jason Rumney * w32.c (stat): When Vw32_get_true_file_attributes is Qlocal, get diff --git a/src/fileio.c b/src/fileio.c index 511cca59fdb..cc6c7c2d3a7 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -2871,7 +2871,6 @@ This is what happens in interactive use with M-x. */) return Qnil; } -#ifdef S_IFLNK DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3, "FMake symbolic link to file: \nGMake symbolic link to file %s: \np", doc: /* Make a symbolic link to FILENAME, named LINKNAME. @@ -2916,6 +2915,7 @@ This happens for interactive use with M-x. */) RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename, linkname, ok_if_already_exists)); +#ifdef S_IFLNK encoded_filename = ENCODE_FILE (filename); encoded_linkname = ENCODE_FILE (linkname); @@ -2942,8 +2942,13 @@ This happens for interactive use with M-x. */) } UNGCPRO; return Qnil; -} + +#else + UNGCPRO; + xsignal1 (Qfile_error, build_string ("Symbolic links are not supported")); + #endif /* S_IFLNK */ +} #ifdef VMS @@ -6779,9 +6784,7 @@ A non-nil value may result in data loss! */); defsubr (&Sdelete_file); defsubr (&Srename_file); defsubr (&Sadd_name_to_file); -#ifdef S_IFLNK defsubr (&Smake_symbolic_link); -#endif /* S_IFLNK */ #ifdef VMS defsubr (&Sdefine_logical_name); #endif /* VMS */ From 37eb1eeae5f3c92611f208ef610206a9f215570e Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Fri, 11 Apr 2008 01:59:14 +0000 Subject: [PATCH 38/56] (autoload-generate-file-autoloads): Bind print-level to ensure output forms aren't truncated if print-level is set to eval-expression-print-level when going via eval-defun and friends, or has been otherwise fiddled with. --- lisp/ChangeLog | 11 +++++++++-- lisp/emacs-lisp/autoload.el | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 646370529ba..1a9de86dd93 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,7 +1,14 @@ +2008-04-11 Kevin Ryde + + * emacs-lisp/autoload.el (autoload-generate-file-autoloads): + Bind print-level to ensure output forms aren't truncated if + print-level is set to eval-expression-print-level when going via + eval-defun and friends, or has been otherwise fiddled with. + 2008-04-09 Michael Albinus - * net/tramp.el (tramp-find-file-name-coding-system-alist): New - defun. + * net/tramp.el (tramp-find-file-name-coding-system-alist): + New defun. (tramp-handle-insert-file-contents, tramp-handle-write-region): Use it. diff --git a/lisp/emacs-lisp/autoload.el b/lisp/emacs-lisp/autoload.el index af9e82b6a4d..0f11fc49ec2 100644 --- a/lisp/emacs-lisp/autoload.el +++ b/lisp/emacs-lisp/autoload.el @@ -301,6 +301,7 @@ Return non-nil in the case where no autoloads were added at point." (substring name 0 (match-beginning 0)) name))) (print-length nil) + (print-level nil) (print-readably t) ; This does something in Lucid Emacs. (float-output-format nil) (done-any nil) From e9e79bdfd44d9f8d6d979035b1f6bdae0fb36b74 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Fri, 11 Apr 2008 02:09:50 +0000 Subject: [PATCH 39/56] Fix up trailer. --- lisp/gnus/nnrss.el | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lisp/gnus/nnrss.el b/lisp/gnus/nnrss.el index 967adcef9f0..658e781a5dc 100644 --- a/lisp/gnus/nnrss.el +++ b/lisp/gnus/nnrss.el @@ -1098,7 +1098,5 @@ prefix), return the prefix." (provide 'nnrss) - +;; arch-tag: 12910c07-0cdf-44fb-8d2c-416ded64c267 ;;; nnrss.el ends here - -;;; arch-tag: 12910c07-0cdf-44fb-8d2c-416ded64c267 From 4d120d6a2a8e780b37f5fd6c50073a9602a46cb9 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Fri, 11 Apr 2008 02:10:54 +0000 Subject: [PATCH 40/56] * maintaining.texi (Maintaining): * emacs.texi (Top): Typo. --- man/ChangeLog | 5 +++++ man/emacs.texi | 2 +- man/maintaining.texi | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/man/ChangeLog b/man/ChangeLog index 474a2dfdbd3..6d8af5334b3 100644 --- a/man/ChangeLog +++ b/man/ChangeLog @@ -1,3 +1,8 @@ +2008-04-11 Mirko Vukovic (tiny change) + + * maintaining.texi (Maintaining): + * emacs.texi (Top): Typo. + 2008-04-09 Michael Albinus * trampver.texi: Update release number. diff --git a/man/emacs.texi b/man/emacs.texi index 485aa640e2a..6b1510d136e 100644 --- a/man/emacs.texi +++ b/man/emacs.texi @@ -715,7 +715,7 @@ Maintaining Large Programs * Change Log:: Maintaining a change history for your program. * Format of ChangeLog:: What the change log file looks like. -* Tags:: Go direct to any function in your program in one +* Tags:: Go directly to any function in your program in one command. Tags remembers which file it is in. * Emerge:: A convenient way of merging two versions of a program. diff --git a/man/maintaining.texi b/man/maintaining.texi index 2215396c992..21c484a4e44 100644 --- a/man/maintaining.texi +++ b/man/maintaining.texi @@ -12,7 +12,7 @@ also particularly useful for this purpose. @menu * Change Log:: Maintaining a change history for your program. * Format of ChangeLog:: What the change log file looks like. -* Tags:: Go direct to any function in your program in one +* Tags:: Go directly to any function in your program in one command. Tags remembers which file it is in. @ifnottex * Emerge:: A convenient way of merging two versions of a program. From d86c6d7dcd34e80f06419cebf102819f99917257 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Fri, 11 Apr 2008 02:27:09 +0000 Subject: [PATCH 41/56] * woman.el (woman2-TH): Quote argument to string-match. --- lisp/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 1a9de86dd93..79c777e3bea 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,7 @@ +2008-04-11 Chong Yidong + + * woman.el (woman2-TH): Quote argument to string-match. + 2008-04-11 Kevin Ryde * emacs-lisp/autoload.el (autoload-generate-file-autoloads): From 95579c3e1d752a2bed7cfda4c3c783b07bacf574 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Fri, 11 Apr 2008 02:27:28 +0000 Subject: [PATCH 42/56] (woman2-TH): Quote argument to string-match. --- lisp/woman.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/woman.el b/lisp/woman.el index 595bb6cc9a1..01e4f223656 100644 --- a/lisp/woman.el +++ b/lisp/woman.el @@ -3810,10 +3810,10 @@ v alters page foot left; m alters page head center. (insert " -- ") (woman-forward-arg 'unquote 'concat) ;; Delete repeated arguments: - (if (string-match (buffer-substring here (point)) + (if (string-match (regexp-quote + (buffer-substring here (point))) (buffer-substring start here)) - (delete-region here (point))) - )) + (delete-region here (point))))) ;; Embolden heading (point is at end of heading): (woman-set-face (save-excursion (beginning-of-line) (point)) (point) 'woman-bold) From 8d0f1197e9a145cbf674e9e410247dc53daef02c Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Fri, 11 Apr 2008 02:31:26 +0000 Subject: [PATCH 43/56] * woman.el (woman2-TH): Use string-equal instead of string-match. --- lisp/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 79c777e3bea..75702835987 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,6 +1,6 @@ 2008-04-11 Chong Yidong - * woman.el (woman2-TH): Quote argument to string-match. + * woman.el (woman2-TH): Use string-equal instead of string-match. 2008-04-11 Kevin Ryde From 42e1d5879b823083eae5e3da4b8b41e6e6b95394 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Fri, 11 Apr 2008 02:31:43 +0000 Subject: [PATCH 44/56] (woman2-TH): Undo last change. Use string-equal instead of string-match. --- lisp/woman.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lisp/woman.el b/lisp/woman.el index 01e4f223656..eca447d07bb 100644 --- a/lisp/woman.el +++ b/lisp/woman.el @@ -3810,8 +3810,7 @@ v alters page foot left; m alters page head center. (insert " -- ") (woman-forward-arg 'unquote 'concat) ;; Delete repeated arguments: - (if (string-match (regexp-quote - (buffer-substring here (point))) + (if (string-equal (buffer-substring here (point)) (buffer-substring start here)) (delete-region here (point))))) ;; Embolden heading (point is at end of heading): From b6924dd73a34d6a4b1047ef821c76802922ffe21 Mon Sep 17 00:00:00 2001 From: Dan Nicolaescu Date: Fri, 11 Apr 2008 03:19:07 +0000 Subject: [PATCH 45/56] Remove hpux10.20 from the desupported list. --- ChangeLog | 4 ++++ configure.in | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2881e87bfc8..aa3f5699ee0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-04-11 Dan Nicolaescu + + * configure.in: Remove hpux10.20 from the desupported list. + 2008-03-26 Chong Yidong * Version 22.2 released. diff --git a/configure.in b/configure.in index eb984a0f821..7608d027515 100644 --- a/configure.in +++ b/configure.in @@ -1271,7 +1271,7 @@ case "${machine}" in esac case "${opsys}" in - bsd386 | bsdos2-1 | bsdos2 | bsdos3 | bsdos4 | bsd4-1 | bsd4-2 | bsd4-3 | usg5-0 | usg5-2-2 | usg5-2 | usg5-3 | ultrix4-3 | 386bsd | hpux | hpux8 | hpux9 | hpux9shr | hpux10 | hpux10-20 | aix3-1 | aix3-2-5 | aix3-2 | aix4-1 | nextstep | ux4800 | uxpds | uxpv ) + bsd386 | bsdos2-1 | bsdos2 | bsdos3 | bsdos4 | bsd4-1 | bsd4-2 | bsd4-3 | usg5-0 | usg5-2-2 | usg5-2 | usg5-3 | ultrix4-3 | 386bsd | hpux | hpux8 | hpux9 | hpux9shr | hpux10 | aix3-1 | aix3-2-5 | aix3-2 | aix4-1 | nextstep | ux4800 | uxpds | uxpv ) echo "The system that you are configuring on: ${canonical} is considered to be obsolete" echo "and it is planned to be desupported in the next version of Emacs" echo "Please email emacs-devel@gnu.org as soon as possible if this system is still in use." From da44dd8487c33726ef29109ab4a221eca7719a12 Mon Sep 17 00:00:00 2001 From: Katsumi Yamaoka Date: Fri, 11 Apr 2008 10:23:49 +0000 Subject: [PATCH 46/56] (BASE_PURESIZE): Increase to 1140000. --- src/ChangeLog | 4 ++++ src/puresize.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ChangeLog b/src/ChangeLog index 1894f6d99ad..0dabe60be18 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2008-04-11 Katsumi Yamaoka + + * puresize.h (BASE_PURESIZE): Increase to 1140000. + 2008-04-10 Michael Albinus * fileio.c (Fmake_symbolic_link): Surround code by #ifdef S_IFLNK diff --git a/src/puresize.h b/src/puresize.h index 23a77646e1e..0306194395b 100644 --- a/src/puresize.h +++ b/src/puresize.h @@ -43,7 +43,7 @@ Boston, MA 02110-1301, USA. */ #endif #ifndef BASE_PURESIZE -#define BASE_PURESIZE (1130000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA) +#define BASE_PURESIZE (1140000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA) #endif /* Increase BASE_PURESIZE by a ratio depending on the machine's word size. */ From 7f9020f1a2f1811e3dc4af358b90007979aa8fb8 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Fri, 11 Apr 2008 17:50:56 +0000 Subject: [PATCH 47/56] (python-mode): Don't mess with hippie-expand. --- lisp/ChangeLog | 4 ++++ lisp/progmodes/python.el | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 75702835987..b0b66d05b77 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,7 @@ +2008-04-11 Stefan Monnier + + * progmodes/python.el (python-mode): Don't mess with hippie-expand. + 2008-04-11 Chong Yidong * woman.el (woman2-TH): Use string-equal instead of string-match. diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index ae863df3b5d..19e9373a5ec 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -2291,9 +2291,11 @@ with skeleton expansions for compound statement templates. (current-column)))) (^ '(- (1+ (current-indentation)))))) (add-hook 'pre-abbrev-expand-hook 'python-pea-hook nil t) - (if (featurep 'hippie-exp) - (set (make-local-variable 'hippie-expand-try-functions-list) - (cons 'python-try-complete hippie-expand-try-functions-list))) + ;; Let's not mess with hippie-expand. Symbol-completion should rather be + ;; bound to another key, since it has different performance requirements. + ;; (if (featurep 'hippie-exp) + ;; (set (make-local-variable 'hippie-expand-try-functions-list) + ;; (cons 'python-try-complete hippie-expand-try-functions-list))) ;; Python defines TABs as being 8-char wide. (set (make-local-variable 'tab-width) 8) (when python-guess-indent (python-guess-indent)) From 4cbb903fcb853c42b32a4101f03dc3c56077b35f Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 11 Apr 2008 18:59:13 +0000 Subject: [PATCH 48/56] (ALL): Move $(CLIENTRES) from here... (all): ...to here. $(ALL) is a prerequisite of .PHONY, so having a real file there is not a good idea. --- nt/ChangeLog | 6 ++++++ nt/makefile.w32-in | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/nt/ChangeLog b/nt/ChangeLog index 6aea7bdc112..b2c31b303c1 100644 --- a/nt/ChangeLog +++ b/nt/ChangeLog @@ -1,3 +1,9 @@ +2008-04-11 Eli Zaretskii + + * makefile.w32-in (ALL): Move $(CLIENTRES) from here... + (all): ...to here. $(ALL) is a prerequisite of .PHONY, so having + a real file there is not a good idea. + 2008-04-10 Jason Rumney * emacsclient.rc: New file. diff --git a/nt/makefile.w32-in b/nt/makefile.w32-in index aef71cfddd9..e9ffd8f5832 100644 --- a/nt/makefile.w32-in +++ b/nt/makefile.w32-in @@ -29,7 +29,7 @@ CLIENTRES = $(BLD)/emacsclient.res XMFLAGS = -ALL = addpm ddeclient runemacs cmdproxy addsection preprep $(CLIENTRES) +ALL = addpm ddeclient runemacs cmdproxy addsection preprep .PHONY: $(ALL) @@ -86,7 +86,7 @@ $(BLD)/addpm.$(O) $(BLD)/ddeclient.$(O) $(BLD)/runemacs.$(O) $(BLD)/cmdproxy.$(O # # Build emacs # -all: which-sh stamp_BLD $(ALL) maybe-bootstrap all-other-dirs-$(MAKETYPE) +all: which-sh stamp_BLD $(ALL) $(CLIENTRES) maybe-bootstrap all-other-dirs-$(MAKETYPE) all-other-dirs-nmake: addsection cd ..\lib-src From a1b41389e4069747940c87b477f11852ec86d9f3 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sat, 12 Apr 2008 01:59:22 +0000 Subject: [PATCH 49/56] [!SYSTEM_MALLOC && !SYNC_INPUT] (uninterrupt_malloc) [HAVE_GTK_AND_PTHREAD && !DOUG_LEA_MALLOC]: Don't use recursive mutex. --- src/ChangeLog | 5 +++++ src/alloc.c | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/ChangeLog b/src/ChangeLog index 0dabe60be18..56676ea95d6 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2008-04-12 YAMAMOTO Mitsuharu + + * alloc.c [!SYSTEM_MALLOC && !SYNC_INPUT] (uninterrupt_malloc) + [HAVE_GTK_AND_PTHREAD && !DOUG_LEA_MALLOC]: Don't use recursive mutex. + 2008-04-11 Katsumi Yamaoka * puresize.h (BASE_PURESIZE): Increase to 1140000. diff --git a/src/alloc.c b/src/alloc.c index 153c54e0264..46887bb332c 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1356,6 +1356,7 @@ void uninterrupt_malloc () { #ifdef HAVE_GTK_AND_PTHREAD +#ifdef DOUG_LEA_MALLOC pthread_mutexattr_t attr; /* GLIBC has a faster way to do this, but lets keep it portable. @@ -1363,6 +1364,11 @@ uninterrupt_malloc () pthread_mutexattr_init (&attr); pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init (&alloc_mutex, &attr); +#else /* !DOUG_LEA_MALLOC */ + /* Some systems such as Solaris 2.6 doesn't have a recursive mutex, + and the bundled gmalloc.c doesn't require it. */ + pthread_mutex_init (&alloc_mutex, NULL); +#endif /* !DOUG_LEA_MALLOC */ #endif /* HAVE_GTK_AND_PTHREAD */ if (__free_hook != emacs_blocked_free) From 108b164dd845dec7fddc154996be9a0ac8e89088 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sat, 12 Apr 2008 02:00:46 +0000 Subject: [PATCH 50/56] (mac-ae-open-documents): Adjust selection range parameter origins. --- lisp/ChangeLog | 5 +++++ lisp/term/mac-win.el | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index b0b66d05b77..292561e6bb9 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2008-04-12 YAMAMOTO Mitsuharu + + * term/mac-win.el (mac-ae-open-documents): Adjust selection range + parameter origins. + 2008-04-11 Stefan Monnier * progmodes/python.el (python-mode): Don't mess with hippie-expand. diff --git a/lisp/term/mac-win.el b/lisp/term/mac-win.el index c9c13c7814e..eaa0e35fa5b 100644 --- a/lisp/term/mac-win.el +++ b/lisp/term/mac-win.el @@ -1738,11 +1738,11 @@ if possible. If there's no such frame, a new frame is created." (let ((line (car selection-range)) (start (cadr selection-range)) (end (nth 2 selection-range))) - (if (> line 0) - (goto-line line) - (if (and (> start 0) (> end 0)) - (progn (set-mark start) - (goto-char end)))))) + (if (>= line 0) + (goto-line (1+ line)) + (if (and (>= start 0) (>= end 0)) + (progn (set-mark (1+ start)) + (goto-char (1+ end))))))) ((stringp search-text) (re-search-forward (mapconcat 'regexp-quote (split-string search-text) "\\|") From fcb49f8bdc2be6d6ca64cab9022d4dffbfd7013d Mon Sep 17 00:00:00 2001 From: YAMAMOTO Mitsuharu Date: Sat, 12 Apr 2008 02:07:41 +0000 Subject: [PATCH 51/56] ** emacs-22.1 with GTK problems (with patches) Fixed. --- admin/FOR-RELEASE | 6 ------ 1 file changed, 6 deletions(-) diff --git a/admin/FOR-RELEASE b/admin/FOR-RELEASE index 79a6f9e261c..335dd535c78 100644 --- a/admin/FOR-RELEASE +++ b/admin/FOR-RELEASE @@ -16,12 +16,6 @@ from 2007-08-27. Impossible to procede without more input from OP (as of 20070912, emails are bouncing) or someone else who can reproduce this. http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg01497.html -** emacs-22.1 with GTK problems (with patches) -Only outstanding issue seems to be whether Solaris 2.6 GTK can be -supported in the absence of recursive mutexes, via a change to -alloc.c, or whether configure should abort. -http://lists.gnu.org/archive/html/bug-gnu-emacs/2007-09/msg00055.html - * BUGS * Bugs and feature requests for 22.3 or later From 2900c113b4d9c9d288e366441a7562647745b86d Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sat, 12 Apr 2008 05:17:39 +0000 Subject: [PATCH 52/56] Docstring change. --- lisp/textmodes/paragraphs.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el index c2e45b217ef..5373da32d66 100644 --- a/lisp/textmodes/paragraphs.el +++ b/lisp/textmodes/paragraphs.el @@ -355,8 +355,8 @@ With argument ARG, do it ARG times; a negative argument ARG = -N means move forward N paragraphs. A paragraph start is the beginning of a line which is a -`first-line-of-paragraph' or which is ordinary text and follows a -paragraph-separating line; except: if the first real line of a +`paragraph-start' or which is ordinary text and follows a +`paragraph-separate'ing line; except: if the first real line of a paragraph is preceded by a blank line, the paragraph starts at that blank line. From 5e01f1ca4989b9466927f48a8a5fdca031fa08dc Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sat, 12 Apr 2008 05:40:15 +0000 Subject: [PATCH 53/56] (makefile-fill-paragraph): Treat indented comments like unindented ones. --- lisp/ChangeLog | 5 +++++ lisp/progmodes/make-mode.el | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 292561e6bb9..0ff3b4178ce 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2008-04-12 Kevin Ryde + + * progmodes/make-mode.el (makefile-fill-paragraph): Treat indented + comments like unindented ones. + 2008-04-12 YAMAMOTO Mitsuharu * term/mac-win.el (mac-ae-open-documents): Adjust selection range diff --git a/lisp/progmodes/make-mode.el b/lisp/progmodes/make-mode.el index 450532a7241..8ebe8f142d4 100644 --- a/lisp/progmodes/make-mode.el +++ b/lisp/progmodes/make-mode.el @@ -1304,7 +1304,7 @@ definition and conveniently use this command." (save-excursion (beginning-of-line) (cond - ((looking-at "^#+\\s-*") + ((looking-at "^[ \t]*#+\\s-*") ;; Found a comment. Return nil to let normal filling take place. nil) From 8d36ea1b23765a62e6b0ffb9d2d49ca33e417edb Mon Sep 17 00:00:00 2001 From: Nick Roberts Date: Sat, 12 Apr 2008 13:11:35 +0000 Subject: [PATCH 54/56] *** empty log message *** --- lisp/ChangeLog | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 0ff3b4178ce..20f04983fbd 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,14 @@ +2008-04-12 Nick Roberts + + * progmodes/gdb-ui.el (gdb-init-buffer): New function. + (gdb-set-gud-minor-mode-existing-buffers) + (gdb-info-breakpoints-custom, gdb-get-location) + (gdb-set-gud-minor-mode-existing-buffers-1): Use it. + Previously gdb-create-define-alist wasn't always run and added to + after-save-hook. + + * progmodes/gud.el (gud-tooltip-tips): Use tooltip-event-buffer + 2008-04-12 Kevin Ryde * progmodes/make-mode.el (makefile-fill-paragraph): Treat indented From 6c6273c6a54a6b7482636e995b1dec27ce385aad Mon Sep 17 00:00:00 2001 From: Nick Roberts Date: Sat, 12 Apr 2008 13:13:32 +0000 Subject: [PATCH 55/56] (gdb-init-buffer): New function. (gdb-set-gud-minor-mode-existing-buffers) (gdb-info-breakpoints-custom, gdb-get-location) (gdb-set-gud-minor-mode-existing-buffers-1): Use it. Previously gdb-create-define-alist wasn't always run and added to after-save-hook. --- lisp/progmodes/gdb-ui.el | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/lisp/progmodes/gdb-ui.el b/lisp/progmodes/gdb-ui.el index c53d1092e00..eee8f00d770 100644 --- a/lisp/progmodes/gdb-ui.el +++ b/lisp/progmodes/gdb-ui.el @@ -483,6 +483,15 @@ otherwise do not." (defconst gdb-source-file-regexp "\\(.+?\\), \\|\\([^, \n].*$\\)") +(defun gdb-init-buffer () + (set (make-local-variable 'gud-minor-mode) + (buffer-local-value 'gud-minor-mode gud-comint-buffer)) + (set (make-local-variable 'tool-bar-map) gud-tool-bar-map) + (when gud-tooltip-mode + (make-local-variable 'gdb-define-alist) + (gdb-create-define-alist) + (add-hook 'after-save-hook 'gdb-create-define-alist nil t))) + (defun gdb-set-gud-minor-mode-existing-buffers () "Create list of source files for current GDB session." (goto-char (point-min)) @@ -495,12 +504,7 @@ otherwise do not." (when (and buffer-file-name (member (file-name-nondirectory buffer-file-name) gdb-source-file-list)) - (set (make-local-variable 'gud-minor-mode) 'gdba) - (set (make-local-variable 'tool-bar-map) gud-tool-bar-map) - (when gud-tooltip-mode - (make-local-variable 'gdb-define-alist) - (gdb-create-define-alist) - (add-hook 'after-save-hook 'gdb-create-define-alist nil t)))))) + (gdb-init-buffer))))) (gdb-force-mode-line-update (propertize "ready" 'face font-lock-variable-name-face))) @@ -1940,10 +1944,7 @@ static char *magick[] = { (not (string-equal file "File not found"))) (with-current-buffer (find-file-noselect file 'nowarn) - (set (make-local-variable 'gud-minor-mode) - 'gdba) - (set (make-local-variable 'tool-bar-map) - gud-tool-bar-map) + (gdb-init-buffer) ;; Only want one breakpoint icon at each ;; location. (save-excursion @@ -3142,9 +3143,7 @@ Add directory to search path for source files using the GDB command, dir.")) (throw 'file-not-found nil)) (with-current-buffer (find-file-noselect (match-string 0)) - (save-current-buffer - (set (make-local-variable 'gud-minor-mode) 'gdba) - (set (make-local-variable 'tool-bar-map) gud-tool-bar-map)) + (gdb-init-buffer) ;; only want one breakpoint icon at each location (save-excursion (goto-line (string-to-number line)) @@ -3166,9 +3165,7 @@ of the current session." buffer-file-name) gdb-source-file-list) (with-current-buffer (find-buffer-visiting buffer-file-name) - (set (make-local-variable 'gud-minor-mode) - (buffer-local-value 'gud-minor-mode gud-comint-buffer)) - (set (make-local-variable 'tool-bar-map) gud-tool-bar-map))))) + (gdb-init-buffer))))) ;;from put-image (defun gdb-put-string (putstring pos &optional dprop &rest sprops) @@ -3493,13 +3490,7 @@ is set in them." (dolist (buffer (buffer-list)) (with-current-buffer buffer (when (member buffer-file-name gdb-source-file-list) - (set (make-local-variable 'gud-minor-mode) - (buffer-local-value 'gud-minor-mode gud-comint-buffer)) - (set (make-local-variable 'tool-bar-map) gud-tool-bar-map) - (when gud-tooltip-mode - (make-local-variable 'gdb-define-alist) - (gdb-create-define-alist) - (add-hook 'after-save-hook 'gdb-create-define-alist nil t))))) + (gdb-init-buffer)))) (gdb-force-mode-line-update (propertize "ready" 'face font-lock-variable-name-face))) From bcb96719b37029024876fca1f65eab69d32aa6d8 Mon Sep 17 00:00:00 2001 From: Nick Roberts Date: Sat, 12 Apr 2008 13:14:56 +0000 Subject: [PATCH 56/56] (gud-tooltip-tips): Use tooltip-event-buffer --- lisp/progmodes/gud.el | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el index 655c7496142..3b8c9628c3b 100644 --- a/lisp/progmodes/gud.el +++ b/lisp/progmodes/gud.el @@ -3401,10 +3401,7 @@ This function must return nil if it doesn't handle EVENT." (if (and (eq gud-minor-mode 'gdba) (not gdb-active-process)) (progn - (with-current-buffer - (window-buffer (let ((mouse (mouse-position))) - (window-at (cadr mouse) - (cddr mouse)))) + (with-current-buffer (tooltip-event-buffer event) (let ((define-elt (assoc expr gdb-define-alist))) (unless (null define-elt) (tooltip-show