2010-07-20 14:10:57 +08:00
;;; rosemacs.el --- Tools for ROS users
;; Copyright (c) 2008, Willow Garage, Inc.
;; All rights reserved.
;;
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions are met:
;;
;; * Redistributions of source code must retain the above copyright
;; notice, this list of conditions and the following disclaimer.
;; * Redistributions in binary form must reproduce the above copyright
;; notice, this list of conditions and the following disclaimer in the
;; documentation and/or other materials provided with the distribution.
;; * Neither the name of the Willow Garage, Inc. nor the names of its
;; contributors may be used to endorse or promote products derived from
;; this software without specific prior written permission.
;;
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;; POSSIBILITY OF SUCH DAMAGE.
;;
;; Author: Bhaskara Marthi
;; Keywords: tools, convenience
;;; Commentary:
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Installation instructions
;; 1. Put this file somewhere (if it's not already in
;; tools/rosemacs in your ros tree)
;;
;; 2. (Optional) From emacs do M-x byte-compile followed by
;; this file's full path
;;
2009-09-15 08:51:16 +08:00
;; 3. Add the following lines to your .emacs
;; (add-to-list 'load-path "/path/to/rosemacs")
2009-09-11 11:08:16 +08:00
;; (require 'rosemacs)
;; (invoke-rosemacs)
;;
2010-07-13 06:08:36 +08:00
;; 4. Add the following line or equivalent to
2009-09-11 11:08:16 +08:00
;; .emacs to activate keyboard shortcuts for the added
2009-09-15 08:51:16 +08:00
;; commands (\C-x\C-r means control-x control-r):
2009-09-11 11:08:16 +08:00
;; (global-set-key "\C-x\C-r" ros-keymap)
;;
2010-07-13 06:08:36 +08:00
;; 5. Make sure the standard ROS variables are set in the
2009-09-15 08:51:16 +08:00
;; emacs process environment. If you follow the standard
;; ROS installation instructions about sourcing .bashrc.ros
;; in your .bashrc, then this will automatically happen
;; if you launch emacs from a bash shell.
2009-09-11 11:08:16 +08:00
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Usage
;;
;; 0. If you did 4 above, you can type the prefix followed
;; by \C-h to see the list of added commands.
;;
;; 1. Directory tracking and tab completion for rosbash
2010-07-20 14:10:57 +08:00
;; commands, including rostopic and rosnode, should now
;; work correctly in shell mode
2009-09-11 11:08:16 +08:00
;;
;; 2. The commands {find|view}-ros-{file|message|service},
;; and view-most-recent-ros-log for navigating the ros
;; libraries are available. Tab completion should work
;; for all of them.
;;
2010-07-13 06:08:36 +08:00
;; 3. The customization option ros-topic-update-interval governs
;; how frequently rosemacs polls the list of ros topics
;; and nodes. Assuming this is positive, it will enable tab
2009-09-11 11:08:16 +08:00
;; completion of ros topics in the shell and for commands
;; such as echo-ros-topic. Additionally, you can use
;; add-hz-update to define a list of topics for which the
;; hz rate is tracked in the background, viewable using
;; display-ros-topic-info.
;;
;; 4. ros-core starts a core. ros-run runs a node. In
;; either case, an appropriately named buffer is created
;; for the new process.
2010-07-13 06:08:36 +08:00
;;
;; 5. ros-launch to start a launch file in a new buffer.
;; Within that buffer, k to kill, r to relaunch.
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2010-07-20 14:10:57 +08:00
;;; Code:
2009-09-11 11:08:16 +08:00
( require 'shell )
( require 'cl )
( require 'warnings )
2009-12-10 02:11:20 +08:00
( require 'time-stamp )
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Parameters
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2010-07-13 06:08:36 +08:00
;; Moved to end of file
2010-04-20 04:41:39 +08:00
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; State
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2010-07-11 11:59:23 +08:00
2009-09-11 11:08:16 +08:00
( defvar ros-packages nil " Vector of ros packages " )
( defvar ros-package-locations nil " Vector of directories containing the items in ros-packages " )
( defvar ros-messages nil " Vector of ros messages " )
( defvar ros-message-packages nil " Vector of packages corresponding to each ros message " )
( defvar ros-services nil " Vector of ros services " )
( defvar ros-service-packages nil " Vector of packages corresponding to each service " )
( defvar ros-root ( getenv " ROS_ROOT " ) )
2009-09-17 06:51:14 +08:00
( defvar ros-topics nil " Vector of current published ros topics " )
2009-09-11 11:08:16 +08:00
( defvar ros-subscribed-topics nil " Subscribed topics " )
2009-09-17 06:51:14 +08:00
( defvar ros-all-topics nil " All topics (generated from published and subscribed) " )
2009-09-11 11:08:16 +08:00
( defvar ros-topic-hertz-processes nil " Alist from topic name to process running rostopic hz on that topic " )
( defvar ros-topic-publication-rates nil " Hash table from topic name to hertz rate of that topic " )
( defvar ros-topic-last-hz-rate nil " Alist from topic name to last time we saw output from rostopic hz " )
2010-07-21 13:02:59 +08:00
( defvar ros-topic-buffer ( get-buffer-create " *ros-topics* " ) " Holds the buffer *ros-topics* if it exists " )
2010-07-13 06:08:36 +08:00
( defvar ros-events-buffer ( get-buffer-create " *ros-events* " ) )
2009-09-11 11:08:16 +08:00
( defvar ros-hz-topic-regexps nil " If a topic name matches one of these, it is hz tracked " )
( defvar ros-topic-timer nil " If non-nil, equals timer object used to schedule calls to rostopic list " )
( defvar ros-num-publishers ( make-hash-table :test 'equal ) " num publishers of a topic " )
( defvar ros-num-subscribers ( make-hash-table :test 'equal ) " num subscribers of a topic " )
2010-04-21 06:28:29 +08:00
( defvar ros-find-args nil )
( defvar ros-find-args-history nil )
2010-07-11 11:59:23 +08:00
( defvar rosemacs/pathname nil " Will hold the path containing this file " )
2010-07-13 06:08:36 +08:00
( defvar rosemacs/invoked t )
( defvar rosemacs/nodes nil " List of nodes " )
( defvar rosemacs/nodes-vec ( vector ) " Vector of nodes " )
2010-04-21 06:28:29 +08:00
2010-04-26 05:16:36 +08:00
( defvar ros-buffer-package nil " A buffer-local variable for caching the current buffer's ros package. " )
( make-variable-buffer-local 'ros-buffer-package )
2010-07-21 13:02:59 +08:00
( with-current-buffer ros-topic-buffer ( insert " Uninitialized (use the display-ros-topic-info command rather than just switching to this buffer) " ) )
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Preloading
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defun ros-load-package-locations ( )
" Reload locations of ros packages by calling out to rospack list "
( interactive )
( with-temp-buffer
( let ( ( l nil ) )
( message " Calling rospack " )
( call-process " rospack " nil t nil " list " )
( goto-char ( point-min ) )
( message " Parsing rospack output " )
( let ( ( done nil ) )
;; Loop over lines; each line contains a package and directory
( while ( not done )
( let ( ( p ( point ) ) )
;; Search for string terminated by space
( setq done ( not ( re-search-forward " [[:space:]] " ( point-max ) t ) ) )
( unless done
( let ( ( package ( buffer-substring p ( 1- ( point ) ) ) ) )
( setq p ( point ) )
;; Search for following string terminated by newline
( re-search-forward " \n " )
( let ( ( dir ( buffer-substring p ( 1- ( point ) ) ) ) )
2010-04-28 07:13:50 +08:00
( push ( cons package dir ) l ) ) ) ) ) ) )
2009-09-11 11:08:16 +08:00
( let ( ( package-alist ( sort* ( vconcat l ) ( lambda ( pair1 pair2 ) ( string< ( car pair1 ) ( car pair2 ) ) ) ) ) )
( setq ros-packages ( map 'vector #' car package-alist )
ros-package-locations ( map 'vector #' cdr package-alist )
ros-messages nil
ros-message-packages nil
ros-services nil
ros-service-packages nil ) )
( message " Done loading ROS package info " ) ) ) )
2010-03-28 11:35:22 +08:00
( defun ros-files-in-package ( dir ext &optional subdir )
2009-09-11 11:08:16 +08:00
" Return list of files in subdirectory ext/ of dir whose extension is .ext "
( with-temp-buffer
( let ( ( l nil )
( done nil )
( p nil ) )
2010-03-28 11:35:22 +08:00
( call-process " ls " nil t nil ( concat dir " / " ( or subdir ext ) " / " ) )
2009-09-11 11:08:16 +08:00
( goto-char ( point-min ) )
( while ( not done )
( setq p ( point ) )
( setq done ( not ( re-search-forward " \\ ([^[:space:]]+ \\ )[[:space:]]+ " ( point-max ) t ) ) )
( unless done
( let ( ( str ( buffer-substring ( match-beginning 1 ) ( match-end 1 ) ) ) )
2010-07-11 11:59:23 +08:00
( let ( ( m ( string-match ( concat " \. " ext " $ " ) str ) ) )
( when m
( push ( substring str 0 m ) l ) ) ) ) ) )
2009-09-11 11:08:16 +08:00
l ) ) )
2010-07-11 11:59:23 +08:00
2009-09-11 11:08:16 +08:00
( defun all-files-in-packages ( ext )
" Look in each package for files with a extension .ext in subdirectory ext/ "
( unless ros-package-locations
( ros-load-package-locations ) )
( let ( ( l nil ) )
( dotimes-with-progress-reporter ( i ( length ros-package-locations ) ) ( concat " Caching locations of . " ext " files: " )
( let ( ( package ( aref ros-packages i ) )
( dir ( aref ros-package-locations i ) ) )
2010-03-28 11:35:22 +08:00
( dolist ( m ( ros-files-in-package dir ext ) )
2009-09-11 11:08:16 +08:00
( push ( cons m package ) l ) ) ) )
( sort* ( vconcat l ) ( lambda ( pair1 pair2 ) ( string< ( car pair1 ) ( car pair2 ) ) ) ) ) )
( defun cache-ros-message-locations ( )
" Look in each package directory for .msg files "
( let ( ( v ( all-files-in-packages " msg " ) ) )
( setq ros-messages ( map 'vector #' car v )
ros-message-packages ( map 'vector #' cdr v ) ) ) )
( defun cache-ros-service-locations ( )
" Look in each package directory for .srv files "
( let ( ( v ( all-files-in-packages " srv " ) ) )
( setq ros-services ( map 'vector #' car v )
ros-service-packages ( map 'vector #' cdr v ) ) ) )
2010-07-11 11:59:23 +08:00
( defun get-rosemacs-path ( )
( message load-file-name )
( let ( ( ind ( string-match " \\ (.* \\ )rosemacs.el$ " load-file-name ) ) )
( if ( not ind )
( warn " Could not determine rosemacs path " )
( match-string 1 load-file-name ) ) ) )
( setq rosemacs/pathname ( get-rosemacs-path ) )
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Lookup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defun ros-package-dir ( package )
( unless ros-package-locations
( ros-load-package-locations ) )
2009-12-10 02:11:20 +08:00
( rosemacs-lookup-vectors package ros-packages ros-package-locations ) )
2009-09-11 11:08:16 +08:00
( defun ros-message-package ( m )
( unless ros-message-packages
( cache-ros-message-locations ) )
2009-12-10 02:11:20 +08:00
( rosemacs-lookup-vectors m ros-messages ros-message-packages ) )
2009-09-11 11:08:16 +08:00
( defun ros-service-package ( m )
( unless ros-service-packages
( cache-ros-service-locations ) )
2009-12-10 02:11:20 +08:00
( rosemacs-lookup-vectors m ros-services ros-service-packages ) )
2009-09-11 11:08:16 +08:00
2010-07-03 02:23:00 +08:00
( defun ros-package-for-path ( path &optional allow-nonexistent )
2010-04-25 10:24:22 +08:00
( let ( ( path ( cond ( ( file-directory-p path )
( directory-file-name path ) )
2010-07-03 02:23:00 +08:00
( ( or ( file-exists-p path ) allow-nonexistent )
2010-04-25 10:24:22 +08:00
( directory-file-name ( file-name-directory path ) ) )
( t nil ) ) ) )
( catch 'done
( while ( and path ( not ( equal path " / " ) ) )
( let ( ( files ( directory-files path ) ) )
( if ( member " manifest.xml " files )
( throw 'done ( file-name-nondirectory path ) )
( setf path ( directory-file-name ( file-name-directory path ) ) ) ) ) ) ) ) )
2010-07-03 02:23:00 +08:00
( defun ros-package-for-buffer ( buffer &optional allow-nonexistent )
2010-04-25 10:24:22 +08:00
( let ( ( fn ( buffer-file-name buffer ) ) )
( when fn
2010-07-03 02:23:00 +08:00
( ros-package-for-path fn allow-nonexistent ) ) ) )
2010-04-25 10:24:22 +08:00
2010-05-20 05:51:26 +08:00
( defun get-buffer-ros-package ( )
( or ros-buffer-package
( setq ros-buffer-package ( ros-package-for-buffer ( current-buffer ) ) ) ) )
2010-04-25 10:24:22 +08:00
( defun ros-current-pkg-modeline-entry ( )
2010-05-20 05:51:26 +08:00
( interactive )
2010-04-26 05:16:36 +08:00
( let ( ( pkg ( or ros-buffer-package ( ros-package-for-buffer ( current-buffer ) ) ) ) )
( unless ros-buffer-package
( if pkg
( setf ros-buffer-package pkg )
( setf ros-buffer-package :none ) ) )
( if ( and pkg ( not ( eq pkg :none ) ) )
2010-04-25 10:24:22 +08:00
( format " (ROS Pkg: %s) " pkg )
" " ) ) )
2009-09-11 11:08:16 +08:00
( defun parse-ros-file-prefix ( str )
" Divide something of the form PACKAGE/DIRS/FILE-PREFIX into its three pieces. Or, if it's just a package prefix, return just that. "
( if ( string-match " \\ ([^/]+ \\ ) \\ (/.* \\ ) " str )
( let ( ( package ( match-string 1 str ) )
( path ( match-string 2 str ) ) )
( if ( string-match " \\ (/.*/ \\ ) \\ ([^/]* \\ ) " path )
( values package ( match-string 1 path ) ( match-string 2 path ) )
( values package " / " ( substring path 1 ) ) ) )
( values str nil nil ) ) )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Completion
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2009-12-10 02:11:20 +08:00
( setq topic-completor ( dynamic-completion-table ( lambda ( str ) ( rosemacs-bsearch str ros-all-topics ) ) ) )
2010-07-13 06:08:36 +08:00
( setq node-completor ( dynamic-completion-table ( lambda ( str ) ( rosemacs-bsearch str rosemacs/nodes-vec ) ) ) )
2009-09-11 11:08:16 +08:00
( setq ros-package-completor
;; Longer because it has to deal with the case of PACKAGE/PATH-PREFIX in addition to PACKAGE-PREFIX
( dynamic-completion-table
( lambda ( str )
( unless ros-packages ( ros-load-package-locations ) )
( multiple-value-bind ( package dir-prefix dir-suffix ) ( parse-ros-file-prefix str )
( if dir-prefix
( let ( ( dir ( concat ( ros-package-dir package ) dir-prefix ) ) )
( let* ( ( files ( directory-files dir nil ( concat " ^ " dir-suffix ) ) )
( comps ( all-completions dir-suffix files ) ) )
( mapcar ( lambda ( comp ) ( concat package dir-prefix comp ) ) comps ) ) )
2009-12-10 02:11:20 +08:00
( rosemacs-bsearch package ros-packages ) ) ) ) ) )
2009-09-11 11:08:16 +08:00
( defun comint-dynamic-complete-ros-package ( )
;; Like the above, except in the shell
( unless ros-packages ( ros-load-package-locations ) )
( let ( ( prefix ( comint-get-ros-package-prefix ) ) )
( when prefix
( multiple-value-bind ( package dir-prefix dir-suffix ) ( parse-ros-file-prefix prefix )
( if dir-prefix
( let ( ( dir ( concat ( ros-package-dir package ) dir-prefix ) ) )
( let ( ( completions ( all-completions dir-suffix ( directory-files dir nil ( concat " ^ " dir-suffix ) ) ) ) )
( comint-dynamic-simple-complete dir-suffix completions )
( skip-syntax-backward " " ) ) )
( progn
2010-07-11 11:59:23 +08:00
( comint-dynamic-simple-complete prefix ( all-completions prefix ros-package-completor ) )
( skip-syntax-backward " " ) ) ) ) ) ) )
2009-09-11 11:08:16 +08:00
( defun comint-dynamic-complete-ros-topic ( )
( let ( ( prefix ( comint-get-ros-topic-prefix ) ) )
( when prefix
( comint-dynamic-simple-complete prefix ( all-completions prefix topic-completor ) )
( skip-syntax-backward " " ) ) ) )
2010-07-13 06:08:36 +08:00
( defun comint-dynamic-complete-ros-node ( )
( let ( ( prefix ( comint-get-ros-node-prefix ) ) )
( when prefix
( comint-dynamic-simple-complete prefix ( all-completions prefix node-completor ) )
( skip-syntax-backward " " ) ) ) )
2009-09-11 11:08:16 +08:00
2010-04-26 09:41:36 +08:00
( defun ros-completing-read-package ( &optional prompt default completion-function )
( unless ros-packages
( ros-load-package-locations ) )
( let ( ( completion-function ( or completion-function ros-completion-function ) )
2010-04-29 07:36:26 +08:00
( prompt ( concat ( or prompt " Enter package " )
2010-04-26 09:41:36 +08:00
( if default
( format " (default `%s' ): " default )
" : " ) ) ) )
( funcall completion-function
2010-04-29 01:43:48 +08:00
prompt ( map 'list ( lambda ( x )
( cons x nil ) )
ros-packages )
2010-04-26 09:41:36 +08:00
nil nil nil nil default ) ) )
( defun ros-completing-read-pkg-file ( prompt &optional default-pkg )
( if ( eq ros-completion-function 'ido-completing-read )
( ros-ido-completing-read-pkg-file prompt default-pkg )
( funcall ros-completion-function prompt ros-package-completor nil nil default-pkg ) ) )
;; Ido completion
( defun ros-ido-completing-read-pkg-file ( prompt &optional default-pkg )
( unless ros-packages
( ros-load-package-locations ) )
2010-04-29 01:43:48 +08:00
( let ( ( old-ido-make-file-list ( symbol-function 'ido-make-file-list-1 ) )
( ros-packages-list ( map 'list #' identity ros-packages ) ) )
2010-04-26 09:41:36 +08:00
( flet ( ( pkg-expr->path ( str )
2010-07-11 11:59:23 +08:00
( let ( ( pkg-name ( second ( split-string str " / " ) ) ) )
( unless ( = ( length pkg-name ) 0 )
( concat ( ros-package-dir pkg-name )
( substring str ( string-match " / " str 1 ) ) ) ) ) ) )
2010-04-26 09:41:36 +08:00
( flet ( ( ido-make-file-list-1 ( dir )
2010-07-11 11:59:23 +08:00
( let ( ( path ( pkg-expr->path dir ) ) )
( if path
( funcall old-ido-make-file-list path )
( mapcar ( lambda ( pkg ) ( concat pkg " / " ) ) ros-packages-list ) ) ) ) )
2010-04-26 09:41:36 +08:00
( substring ( ido-read-file-name prompt " / "
2010-04-29 01:43:48 +08:00
( when ( member default-pkg ros-packages-list )
2010-04-26 09:41:36 +08:00
default-pkg ) )
1 ) ) ) ) )
( defun ros-completing-read-message ( prompt &optional default )
( unless ros-messages
( cache-ros-message-locations ) )
2010-05-09 08:04:42 +08:00
( let* ( ( ros-messages-list ( map 'list 'identity ros-messages ) )
( result ( funcall ros-completion-function prompt
2010-07-11 11:59:23 +08:00
( map 'list ( lambda ( m pkg )
( cons ( if ( > ( count m ros-messages-list :test 'equal ) 1 )
( format " %s (%s) " m pkg )
m )
nil ) )
ros-messages-list ros-message-packages )
nil nil nil nil ( when ( member default ros-messages-list )
default ) ) )
2010-05-23 14:25:38 +08:00
( ws-pos ( position ?\s result ) )
( message ( substring result 0 ws-pos ) )
( package ( when ws-pos
( let ( ( package-str ( substring result ws-pos ) ) )
( substring package-str 2 ( - ( length package-str ) 1 ) ) ) ) ) )
( if package
( concatenate 'string package " / " message )
message ) ) )
2010-04-26 09:41:36 +08:00
( defun ros-completing-read-service ( prompt &optional default )
( unless ros-services
( cache-ros-service-locations ) )
2010-05-23 14:25:38 +08:00
( let* ( ( ros-services-list ( map 'list 'identity ros-services ) )
( result ( funcall ros-completion-function prompt
2010-07-11 11:59:23 +08:00
( map 'list ( lambda ( m pkg )
( cons ( if ( > ( count m ros-services-list :test 'equal ) 1 )
( format " %s (%s) " m pkg )
m )
nil ) )
ros-services-list ros-service-packages )
nil nil nil nil ( when ( member default ros-services-list )
default ) ) )
2010-05-23 14:25:38 +08:00
( ws-pos ( position ?\s result ) )
( service ( substring result 0 ws-pos ) )
( package ( when ws-pos
( let ( ( package-str ( substring result ws-pos ) ) )
( substring package-str 2 ( - ( length package-str ) 1 ) ) ) ) ) )
( if package
( concatenate 'string package " / " service )
service ) ) )
2010-04-26 09:41:36 +08:00
( defun ros-completing-read-topic ( prompt &optional default )
2010-04-29 01:43:48 +08:00
( funcall ros-completion-function prompt ( map 'list ( lambda ( m )
( cons m nil ) )
ros-all-topics )
2010-05-09 08:04:42 +08:00
nil nil nil nil ( when ( member default ( map 'list 'identity ros-all-topics ) )
2010-04-26 09:41:36 +08:00
default ) ) )
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Navigation commands
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defun find-ros-file ( package-name &optional dont-reload )
" Open up the directory corresponding to PACKAGE-NAME in dired mode. If used interactively, tab completion will work. "
2010-04-26 09:41:36 +08:00
( interactive ( list ( ros-completing-read-pkg-file " Enter ros path: " ) nil ) )
2009-09-11 11:08:16 +08:00
( multiple-value-bind ( package dir-prefix dir-suffix ) ( parse-ros-file-prefix package-name )
( let* ( ( package-dir ( ros-package-dir package ) )
( path ( if dir-prefix ( concat package-dir dir-prefix dir-suffix ) package-dir ) ) )
( if path
( find-file path )
( if dont-reload
( error " Did not find %s in the ros package list. " package-name )
( progn
2010-07-11 11:59:23 +08:00
( lwarn ' ( rosemacs ) :debug " Did not find %s. Reloading ros package list and trying again... " package-name )
( ros-load-package-locations )
( find-ros-file package-name t ) ) ) ) ) ) )
2009-09-11 11:08:16 +08:00
( defun view-ros-file ( ros-file-name &optional dont-reload )
" View (open in read-only mode with simpler editing commands — see emacs help) the file corresponding to ROS-FILE-NAME (in form packagename/filename). If used interactively, tab completion will work. "
2010-04-26 09:41:36 +08:00
( interactive ( list ( ros-completing-read-pkg-file " Enter ros path: " ) nil ) )
2009-09-11 11:08:16 +08:00
( multiple-value-bind ( package dir-prefix dir-suffix ) ( parse-ros-file-prefix ros-file-name )
( let* ( ( package-dir ( ros-package-dir package ) )
( path ( if dir-prefix ( concat package-dir dir-prefix dir-suffix ) package-dir ) ) )
( if path
( view-file-other-window path )
( if dont-reload
( error " Did not find %s in the ros package list. " ros-file-name )
( progn
2010-07-11 11:59:23 +08:00
( lwarn ' ( rosemacs ) :debug " Did not find %s. Reloading ros package list and trying again... " ros-file-name )
( ros-load-package-locations )
( view-ros-file ros-file-name t ) ) ) ) ) ) )
2009-09-11 11:08:16 +08:00
( defun find-ros-message ( message )
" Open definition of a ros message. If used interactively, tab completion will work. "
2010-04-26 09:41:36 +08:00
( interactive ( list ( ros-completing-read-message
( if ( current-word t t )
( format " Enter message name (default %s): " ( current-word t t ) )
" Enter message name: " )
( current-word t t ) ) ) )
2010-05-23 14:25:38 +08:00
( let* ( ( p+m ( split-string message " / " ) )
( p ( if ( cdr p+m )
( car p+m )
( ros-message-package message ) ) )
( m ( car ( last p+m ) ) ) )
( unless p
( error " Could not find package for message %s " message ) )
( let ( ( dir ( ros-package-dir p ) ) )
( unless dir
( error " Could not find directory corresponding to package %s " p ) )
( find-file ( concat dir " /msg/ " m " .msg " ) ) ) ) )
2009-09-11 11:08:16 +08:00
( defun find-ros-service ( service )
" Open definition of a ros service. If used interactively, tab completion will work. "
2010-04-26 09:41:36 +08:00
( interactive ( list ( ros-completing-read-service
( if ( current-word t t )
( format " Enter service name (default %s): " ( current-word t t ) )
" Enter service name: " )
( current-word t t ) ) ) )
2010-05-23 14:25:38 +08:00
( let* ( ( p+m ( split-string service " / " ) )
( p ( if ( cdr p+m )
( car p+m )
( ros-service-package service ) ) )
( m ( car ( last p+m ) ) ) )
( unless p
( error " Could not find package for service %s " service ) )
( let ( ( dir ( ros-package-dir p ) ) )
( unless dir
( error " Could not find directory corresponding to package %s " p ) )
( find-file ( concat dir " /srv/ " m " .srv " ) ) ) ) )
2009-09-11 11:08:16 +08:00
2009-12-10 02:11:20 +08:00
;; (defun view-ros-message (message)
;; "Open definition of a ros message in view mode. If used interactively, tab completion will work."
;; (interactive (list (completing-read
;; (if (current-word t t)
;; (format "Enter message name (default %s): " (current-word t t))
;; "Enter message name: ")
;; message-completor nil nil nil nil (current-word t t))))
;; (let ((p (ros-message-package message)))
;; (if p
;; (let ((dir (ros-package-dir p)))
;; (if dir
;; (view-file-other-window (concat dir "/msg/" message ".msg"))
;; (error "Could not find directory corresponding to package %s" p)))
;; (error "Could not find package for message %s" message))))
2009-09-11 11:08:16 +08:00
( defun view-ros-message ( message )
2010-04-26 09:41:36 +08:00
" Open definition of a ros message in view mode. If used interactively, tab completion will work. "
( interactive ( list ( ros-completing-read-message
( if ( current-word t t )
( format " Enter message name (default %s): " ( current-word t t ) )
" Enter message name: " )
( current-word t t ) ) ) )
( shell-command ( format " rosmsg show %s " message ) ) )
2009-09-11 11:08:16 +08:00
( defun view-ros-service ( service )
" Open definition of a ros service in view mode. If used interactively, tab completion will work. "
2010-04-26 09:41:36 +08:00
( interactive ( list ( ros-completing-read-service
( if ( current-word t t )
( format " Enter service name (default %s): " ( current-word t t ) )
" Enter service name: " )
( current-word t t ) ) ) )
2010-05-23 14:25:38 +08:00
( shell-command ( format " rossrv show %s " service ) ) )
2009-09-11 11:08:16 +08:00
2010-04-26 09:41:36 +08:00
( defun ros-rgrep-package ( ros-pkg regexp files )
" Run a recursive grep in `ros-pkg' , with `regexp' as search
pattern and ` files ' as file pattern. This function is similar to
RGREP but with a ros package instead of a directory as
parameter. "
( interactive ( progn ( grep-compute-defaults )
2010-04-29 07:36:26 +08:00
( let ( ( package ( ros-completing-read-package
2010-05-20 05:51:26 +08:00
nil ( get-buffer-ros-package ) ) )
2010-04-26 09:41:36 +08:00
( regexp ( grep-read-regexp ) ) )
( list
package
regexp
( grep-read-files regexp ) ) ) ) )
( rgrep regexp files ( ros-package-path ros-pkg ) ) )
2009-09-11 11:08:16 +08:00
2010-04-26 09:41:36 +08:00
( defun ros-find-dired ( ros-pkg args )
" Run find in ros package `ros-pkg' with arguments `args' and
load the result in a dired buffer. This function is similar to
FIND-DIRED but with a ros package instead of a directory as
parameter. "
2010-04-29 07:36:26 +08:00
( interactive ( list ( ros-completing-read-package
2010-05-20 05:51:26 +08:00
nil ( get-buffer-ros-package ) )
2010-04-26 09:41:36 +08:00
( read-string " Run find (within args): " ros-find-args
' ( ros-find-args-history . 1 ) ) ) )
( find-dired ( ros-package-path ros-pkg ) args ) )
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Core
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defun ros-core ( )
( interactive )
( if ( get-buffer " *roscore* " )
( switch-to-buffer ( get-buffer " *roscore* " ) )
( progn ( start-process " roscore " ( get-buffer-create " *roscore* " ) " roscore " )
( message " roscore started " ) ) ) )
( defun ros-set-master-uri ( host port )
" Set the master uri used by other commands (e.g. rostopic) "
( interactive " sEnter master uri host: \n nEnter master uri port: " )
( let ( ( uri ( format " http://%s:%d " host port ) ) )
( setenv " ROS_MASTER_URI " uri )
( message " Set ROS_MASTER_URI to %s " uri ) ) )
2010-07-13 06:08:36 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; rosnode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defun rosemacs/parse-node-list ( start finish )
( lwarn ' ( rosemacs ) :debug " Parsing node list " )
( goto-char start )
( let ( ( current-nodes nil ) )
( while ( re-search-forward " ^ \\ / \\ (.* \\ )$ " nil t )
( when ( > ( match-end 0 ) finish )
( return ) )
( push ( match-string 1 ) current-nodes ) )
( let ( ( sorted-nodes ( sort* current-nodes 'string< ) ) )
( destructuring-bind ( added deleted )
( rosemacs-list-diffs rosemacs/nodes sorted-nodes )
( setq rosemacs/nodes sorted-nodes
rosemacs/nodes-vec ( vconcat rosemacs/nodes ) )
( save-excursion
( set-buffer ( get-buffer-create " *ros-nodes* " ) )
( erase-buffer )
( dolist ( n rosemacs/nodes )
( insert n )
( insert " \n " ) ) )
( when added
( lwarn ' ( rosemacs ) :debug " New nodes: %s " added )
( rosemacs/add-event ( format " New nodes: %s " added ) ) )
( let ( ( l ( length deleted ) ) )
( when ( > l 0 )
( if ( = l 1 )
( rosemacs/add-event ( format " Ros node %s exited " ( first deleted ) ) t )
( rosemacs/add-event ( format " %s ros nodes exited: %s " l deleted ) t ) ) ) ) ) ) ) )
( defun rosemacs/rosnode-filter ( proc str )
( with-current-buffer ( process-buffer proc )
( goto-char ( point-max ) )
( insert str )
( let ( ( found-start ( re-search-backward " BEGIN ROSNODE LIST$ " nil t ) ) )
( if found-start
( let* ( ( start-pt ( match-end 0 ) )
( found-finish ( re-search-forward " END ROSNODE LIST$ " nil t ) ) )
( when found-finish
( rosemacs/parse-node-list start-pt ( match-beginning 0 ) )
( delete-region ( point-min ) ( match-end 0 ) ) ) ) ) )
) )
( defun rosemacs/track-nodes ( interval )
( interactive " nEnter rosnode update interval in seconds (0 to stop tracking) " )
( let ( ( name " *rosnode-tracker* " ) )
( let ( ( old-proc ( get-process name ) ) )
( when old-proc
( message " Cancelling existing rosnode tracker " )
;; doesn't seem to respond to sigint reliably
( delete-process old-proc ) )
( when ( > interval 0 )
( let ( ( proc ( start-process name name ( concat rosemacs/pathname " poll-rosnode " ) ( format " %s " interval ) ) ) )
2010-07-20 14:10:57 +08:00
( set-process-query-on-exit-flag proc nil )
2010-07-13 06:08:36 +08:00
( set-process-filter proc 'rosemacs/rosnode-filter ) ) )
) ) )
( defun rosemacs/display-nodes ( )
( interactive )
( display-buffer " *ros-nodes* " ) )
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; rostopic
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2010-07-13 06:08:36 +08:00
2010-07-11 11:59:23 +08:00
( defun rosemacs-topic-filter ( proc str )
( with-current-buffer ( process-buffer proc )
( goto-char ( point-max ) )
( insert str )
( let ( ( found-start ( re-search-backward " BEGIN ROSTOPIC LIST$ " nil t ) ) )
( if found-start
2010-07-13 06:08:36 +08:00
( let* ( ( start-point ( match-end 0 ) )
( found-finish ( re-search-forward " END ROSTOPIC LIST " nil t ) ) )
2010-07-11 11:59:23 +08:00
( if found-finish
( let ( ( finish-pt ( match-beginning 0 ) ) )
( rosemacs/parse-topic-list start-point finish-pt )
( delete-region ( point-min ) finish-pt ) )
) ) ) ) ) )
( defun rosemacs/track-topics ( interval )
( interactive " nEnter rostopic update interval in seconds (0 to stop tracking). " )
( let ( ( name " *rostopic-tracker* " ) )
( let ( ( old-proc ( get-process name ) ) )
2010-07-13 06:08:36 +08:00
( when old-proc
2010-07-11 11:59:23 +08:00
( message " Cancelling existing rostopic tracker " )
2010-07-13 06:08:36 +08:00
( delete-process old-proc )
) )
2010-07-11 11:59:23 +08:00
( when ( > interval 0 )
( let ( ( proc ( start-process name name ( concat rosemacs/pathname " poll-rostopic " ) ( format " %s " interval ) ) ) )
2010-07-20 14:10:57 +08:00
( set-process-query-on-exit-flag proc nil )
2010-07-21 13:02:59 +08:00
( set-process-filter proc 'rosemacs-topic-filter ) )
) ) )
2009-09-11 11:08:16 +08:00
( defun display-ros-topic-info ( )
" Display current ros topic info in *ros-topics* buffer "
( interactive )
( let ( ( buf ( get-buffer " *ros-topics* " ) ) )
( if buf
( switch-to-buffer buf )
( progn
( setq ros-topic-buffer ( get-buffer-create " *ros-topics* " ) )
( switch-to-buffer ros-topic-buffer )
2010-07-08 14:20:27 +08:00
( ros-topic-list-mode 1 ) ) )
2009-09-11 11:08:16 +08:00
( update-ros-topic-buffer ) ) )
( defun add-hz-update ( topic-regexp )
2010-04-26 09:41:36 +08:00
( interactive ( list ( ros-completing-read-topic " Enter topic name or regexp to track: " ) ) )
2009-09-11 11:08:16 +08:00
( push topic-regexp ros-hz-topic-regexps )
( dolist ( topic ros-topics )
( when ( string-match topic-regexp topic )
( unless ( assoc topic ros-topic-last-hz-rate )
( start-hz-tracker topic ) ) ) ) )
2010-07-11 11:59:23 +08:00
2009-09-11 11:08:16 +08:00
( defun remove-hz-update ( topic-regexp )
2010-04-26 09:41:36 +08:00
( interactive ( list ( funcall ros-completion-function " Enter regexp to stop tracking: " ros-hz-topic-regexps ) ) )
2009-09-11 11:08:16 +08:00
( setq ros-hz-topic-regexps ( delete topic-regexp ros-hz-topic-regexps ) )
( dolist ( pair ros-topic-last-hz-rate )
( let ( ( topic ( car pair ) ) )
( when ( string-match topic-regexp topic )
( stop-hz-tracker topic ) ) ) ) )
( defun echo-ros-topic ( topic )
" Create a new buffer in which rostopic echo is done on the given topic (read interactively, with tab-completion) "
( interactive ( list ( let ( ( word ( current-word ) ) )
2010-04-26 09:41:36 +08:00
( ros-completing-read-topic
( if word
( format " Enter topic name (default %s): " word )
" Enter topic name: " )
word ) ) ) )
2009-09-11 11:08:16 +08:00
( let* ( ( topic-full-name ( if ( string-match " ^/ " topic ) topic ( concat " / " topic ) ) )
2010-04-26 09:41:36 +08:00
( buffer-name ( concat " *rostopic: " topic-full-name " * " ) )
( process ( start-process buffer-name buffer-name " rostopic " " echo " topic-full-name ) ) )
( view-buffer-other-window ( process-buffer process ) )
2010-07-08 14:20:27 +08:00
( ros-topic-echo-mode 1 ) ) )
2009-09-11 11:08:16 +08:00
2009-09-17 06:51:14 +08:00
( defun ros-topic-info ( topic )
2010-04-26 09:41:36 +08:00
" Print info about topic, using rostopic info "
2009-09-17 06:51:14 +08:00
( interactive ( list ( let ( ( word ( current-word ) ) )
2010-04-26 09:41:36 +08:00
( ros-completing-read-topic
( if word
( format " Enter topic name (default %s): " word )
" Enter topic name: " )
word ) ) ) )
2009-09-17 06:51:14 +08:00
( let* ( ( topic-full-name ( if ( string-match " ^/ " topic ) topic ( concat " / " topic ) ) )
2010-04-26 09:41:36 +08:00
( buffer-name ( format " *rostopic-info:%s " topic ) )
2010-04-26 10:15:39 +08:00
( buf ( get-buffer-create buffer-name ) ) )
( with-current-buffer buf
( let ( ( buffer-read-only nil ) )
( erase-buffer ) ) )
( view-buffer-other-window buf )
( call-process " rostopic " nil buf t " info " topic-full-name ) ) )
2009-09-11 11:08:16 +08:00
2010-07-11 11:59:23 +08:00
( defun rosemacs/interrupt-process ( )
2009-09-11 11:08:16 +08:00
( interactive )
( interrupt-process ) )
( defun kill-current-buffer ( )
( interactive )
2010-07-11 11:59:23 +08:00
( let ( ( process ( get-buffer-process ( current-buffer ) ) ) )
2009-12-10 02:11:20 +08:00
( when ( and process ( eq ( process-status process ) 'run ) )
( interrupt-process ) ) )
2009-09-11 11:08:16 +08:00
( kill-buffer nil ) )
( defvar ros-topic-echo-keymap ( make-sparse-keymap ) )
2010-07-11 11:59:23 +08:00
( define-key ros-topic-echo-keymap " k " 'rosemacs/interrupt-process )
2009-09-11 11:08:16 +08:00
( define-key ros-topic-echo-keymap " q " 'kill-current-buffer )
( define-minor-mode ros-topic-echo-mode
" Mode used for rostopic echo.
k kills the process ( sends SIGINT ) .
q kills the buffer and process "
:init-value nil
:lighter " ros-topic-echo "
:keymap ros-topic-echo-keymap
( message " ros-topic-echo-mode: k to stop, q to quit " ) )
( defvar ros-topic-list-keymap ( make-sparse-keymap ) )
( define-key ros-topic-list-keymap [ ?q ] 'kill-current-buffer )
( define-key ros-topic-list-keymap [ ?\r ] 'echo-current-topic )
( define-key ros-topic-list-keymap [ ?h ] 'hz-current-topic )
( define-key ros-topic-list-keymap [ ?H ] 'unhz-current-topic )
2009-09-17 06:51:14 +08:00
( define-key ros-topic-list-keymap [ ?i ] 'ros-topic-info )
2009-09-11 11:08:16 +08:00
( defun hz-current-topic ( )
( interactive )
( add-hz-update ( ros-emacs-current-word ) ) )
( defun unhz-current-topic ( )
( interactive )
( remove-hz-update ( ros-emacs-current-word ) ) )
( defun echo-current-topic ( )
( interactive )
( echo-ros-topic ( ros-emacs-current-word ) ) )
( define-minor-mode ros-topic-list-mode
" Mode used for *ros-topics* buffer
q kills buffer "
:init-value nil
:keymap ros-topic-list-keymap
( message " ros-topic-mode: enter to echo, h/H to start/stop hertz tracking, q to quit " ) )
( defun update-ros-topic-buffer ( )
2010-07-11 11:59:23 +08:00
" Use the current value of ros-topic related variables to reset the contents of the *ros-topics* buffer "
2009-09-11 11:08:16 +08:00
( when ( and ros-topic-buffer ( get-buffer-window ros-topic-buffer ) )
( if ( equal ( current-buffer ) ros-topic-buffer )
( let ( ( old-point ( point ) ) )
( update-ros-topic-buffer-helper )
( goto-char ( min ( point-max ) old-point ) ) )
( save-excursion
( update-ros-topic-buffer-helper ) ) ) ) )
2009-12-10 02:11:20 +08:00
( defun ros-topic-get-stamp-string ( )
( goto-char ( point-min ) )
( let ( ( pos ( re-search-forward " ^ \\ (Last updated.* \\ )$ " nil t ) ) )
( if pos
( match-string 1 )
" Last updated: <> " ) ) )
2009-09-11 11:08:16 +08:00
( defun update-ros-topic-buffer-helper ( )
( set-buffer ros-topic-buffer )
2009-12-10 02:11:20 +08:00
( let ( ( old-stamp ( ros-topic-get-stamp-string ) ) )
( erase-buffer )
( princ ( format " Master uri: %s \n " ( getenv " ROS_MASTER_URI " ) ) ros-topic-buffer )
( princ old-stamp ros-topic-buffer ) )
2009-09-11 11:08:16 +08:00
( when ros-topic-publication-rates
( princ ( format " \n Hz-tracked topics: \n " ) ros-topic-buffer )
( dolist ( topic ros-topics )
( let ( ( rate-pair ( assoc topic ros-topic-publication-rates ) ) )
( when rate-pair
( let ( ( rate ( cdr rate-pair ) )
( diff ( - ( second ( current-time ) ) ( or ( cdr ( assoc topic ros-topic-last-hz-rate ) ) 0.0 ) ) ) )
( if rate
( if ( > diff ros-topic-timeout-rate )
( princ ( format " %s : %s (as of %s seconds ago) " topic rate diff ) ros-topic-buffer )
( princ ( format " %s : %s " topic rate ) ros-topic-buffer ) )
( princ ( format " %s : not yet known " topic ) ros-topic-buffer ) ) )
( terpri ros-topic-buffer ) ) ) )
( terpri ros-topic-buffer ) )
( princ ( format " \n Topic, #pubs, #subs \n \n " ) ros-topic-buffer )
2009-12-10 02:11:20 +08:00
2009-09-17 06:51:14 +08:00
( dotimes ( i ( length ros-all-topics ) )
( let ( ( topic ( aref ros-all-topics i ) ) )
( princ ( format " %s %s %s " topic ( gethash topic ros-num-publishers 0 ) ( gethash topic ros-num-subscribers 0 ) ) ros-topic-buffer )
( terpri ros-topic-buffer ) ) ) )
2009-09-11 11:08:16 +08:00
2010-07-11 11:59:23 +08:00
( defun rosemacs/get-topics ( start end h )
2009-09-11 11:08:16 +08:00
( let ( ( done nil ) ( current-topics nil ) )
( goto-char start )
( while ( not done )
( let ( ( pos ( re-search-forward " ^ \\ s-* \\ * \\ s-* \\ ( \\ S-* \\ ) \\ [.* \\ ] \\ ( \\ S-* \\ ) " end t ) ) )
( if pos
( let ( ( topic ( match-string 1 ) ) )
( push topic current-topics )
( setf ( gethash topic h ) ( match-string 2 ) ) )
( setq done t ) ) ) )
( sort* current-topics 'string< ) ) )
2010-07-13 06:08:36 +08:00
2010-07-11 11:59:23 +08:00
( defun rosemacs/parse-topic-list ( start finish )
2009-09-11 11:08:16 +08:00
( lwarn ' ( rosemacs ) :debug " Parsing rostopic list " )
2010-07-11 11:59:23 +08:00
( goto-char start )
( let ( ( pub-start ( re-search-forward " Published topics: " nil t ) )
( sub-start ( or ( re-search-forward " Subscribed topics: " nil t ) ( point-max ) ) ) )
( if ( and pub-start sub-start )
( let ( ( new-published-topics ( rosemacs/get-topics pub-start sub-start ros-num-publishers ) ) )
( setq ros-subscribed-topics ( rosemacs/get-topics sub-start ( point-max ) ros-num-subscribers ) )
( destructuring-bind ( added deleted ) ( rosemacs-list-diffs ros-topics new-published-topics )
( lwarn ' ( rosemacs ) :debug " added topics : %s " added )
( dolist ( topic added )
( add-ros-topic topic ) )
( dolist ( topic deleted )
( remove-ros-topic topic ) ) ) )
2010-07-13 06:08:36 +08:00
( lwarn ' ( rosemacs ) :debug " rostopic output did not look as expected; could just be that the master is not up. " ) ) )
2010-07-11 11:59:23 +08:00
( lwarn ' ( rosemacs ) :debug " Done parsing rostopic list " )
( setq ros-all-topics
( sort* ( remove-duplicates ( vconcat ros-topics ros-subscribed-topics ) :test 'equal ) 'string< ) )
;; update display
( save-excursion
( when ros-topic-buffer
( set-buffer ros-topic-buffer )
( update-ros-topic-buffer )
( let ( ( time-stamp-pattern " 5/^Last updated: <%02H:%02M:%02S " ) )
( time-stamp ) ) ) ) )
2009-09-11 11:08:16 +08:00
( defun remove-ros-topic ( topic )
" Remove this topic and all associated entries from topic list, completion list, hertz processes, publication rates "
2010-07-13 06:08:36 +08:00
( lwarn ' ( rosemacs ) :debug " removing ros topic %s " topic )
2009-09-11 11:08:16 +08:00
( stop-hz-tracker topic )
( setq ros-topics ( delete topic ros-topics ) )
)
( defun stop-hz-tracker ( topic )
( let ( ( pair ( assoc topic ros-topic-hertz-processes ) ) )
( when pair ( kill-buffer ( process-buffer ( cdr pair ) ) ) ) )
( setq ros-topic-hertz-processes ( delete-if ( lambda ( pair ) ( equal ( car pair ) topic ) ) ros-topic-hertz-processes )
ros-topic-publication-rates ( delete-if ( lambda ( pair ) ( equal ( car pair ) topic ) ) ros-topic-publication-rates )
ros-topic-last-hz-rate ( delete-if ( lambda ( pair ) ( equal ( car pair ) topic ) ) ros-topic-last-hz-rate ) ) )
( defun set-ros-topic-hz ( topic rate )
" Set hertz rate of topic. Also, update the last-published-hertz-rate timestamp of the topic "
( let ( ( rate-pair ( assoc topic ros-topic-publication-rates ) ) )
( if rate-pair
( setf ( cdr rate-pair ) rate )
( push ( cons topic rate ) ros-topic-publication-rates ) ) )
( let ( ( last-time-pair ( assoc topic ros-topic-last-hz-rate ) )
( time-in-seconds ( second ( current-time ) ) ) )
( if last-time-pair
( setf ( cdr last-time-pair ) time-in-seconds )
( push ( cons topic time-in-seconds ) ros-topic-last-hz-rate ) ) )
( lwarn ' ( rosemacs ) :debug " Updated hz for topic %s " topic ) )
( defun ros-topic-hz-filter ( proc string )
" Given the hertz process and string containing output from it, update the entry for the corresponding topic's publication rate "
( let ( ( pair ( rassoc proc ros-topic-hertz-processes ) ) )
( if pair
( let ( ( hz ( ros-topic-extract-hz string ) )
( topic ( car pair ) ) )
( cond
( ( eql hz 'not-published ) ( remove-ros-topic topic ) )
( hz ( set-ros-topic-hz topic hz ) ) ) )
( lwarn ' ( rosemacs ) :warning " Unexpectedly could not find topic corresponding to process %s " ( process-name proc ) ) ) ) )
( defun ros-topic-extract-hz ( string )
" Given a string, if it contains something that looks like a hz reading, return the first such one, else if it contains error, return the string error, else if not published yet, return the number -1, else return nil "
;; This will not work well if the process filter ends up being called too frequently, in which case no one call will match the regexp.
;; Empirically, that does not seem to happen.
( let ( ( case-fold-search t ) )
( cond
( ( string-match " error " string ) " error " )
( ( string-match " average rate: \\ ([0-9]+ \\ .[0-9]* \\ ) " string ) ( match-string 1 string ) )
( ( string-match " does not appear to be published yet " string ) 'not-published ) ) ) )
( defun start-hz-tracker ( topic )
( let* ( ( name ( concat " rostopic-hz- " topic ) )
( proc ( start-process name name " rostopic " " hz " topic ) ) )
( push ( list topic ) ros-topic-last-hz-rate )
( push ( list topic ) ros-topic-publication-rates )
( let ( ( old-proc-pair ( assoc topic ros-topic-hertz-processes ) ) )
( if old-proc-pair
( progn
( kill-buffer ( process-buffer ( cdr old-proc-pair ) ) )
( setf ( cdr old-proc-pair ) proc ) )
( push ( cons topic proc ) ros-topic-hertz-processes ) ) )
( set-process-filter proc 'ros-topic-hz-filter ) ) )
( defun satisfies-hz-regexps ( topic )
( some ( lambda ( regexp ) ( string-match regexp topic ) ) ros-hz-topic-regexps ) )
( defun add-ros-topic ( topic )
" Post: topic is added to the list of topics and related bookkeeping done: list of completions is regenerated, hertz process is started and added to list, publication-rate entry is added to list "
( let ( ( pair ( assoc topic ros-topic-publication-rates ) ) )
( when pair ( setq ros-topic-publication-rates ( delete pair ros-topic-publication-rates ) ) ) )
( when ( satisfies-hz-regexps topic )
( start-hz-tracker topic ) )
( push topic ros-topics )
( setq ros-topics ( sort* ros-topics 'string< ) )
2009-09-17 06:51:14 +08:00
2009-09-11 11:08:16 +08:00
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shell mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defun ros-directory-tracker ( str )
" Keep buffer current directory up-to-date in the presence of roscd. This is analogous to shell-directory-tracker in shell.el though not as thorough about special cases. It will not work with variable substitution, any sort of program control, etc - only for simple commands and pipelines of the same. If it gets confused, do M-x shell-resync-dirs. "
;; Might be simpler to just call shell-resync-dirs at some point
;; skip whitespace
( let ( ( start ( progn ( string-match
( concat " ^ " shell-command-separator-regexp ) str )
( match-end 0 ) ) )
end cmd arg1 )
( while ( string-match shell-command-regexp str start )
( setq end ( match-end 0 )
cmd ( comint-arguments ( substring str start end ) 0 0 )
arg1 ( comint-arguments ( substring str start end ) 1 1 ) )
( when arg1 ( setq arg1 ( shell-unquote-argument arg1 ) ) )
( cond ( ( string-match " ^ros[cp]d \\ ([[:space:]] \\ |$ \\ ) " cmd )
( if ( string-match " \\ ([^/]* \\ )/ \\ (.* \\ ) " arg1 )
( let ( ( package ( match-string 1 arg1 ) )
( subdir ( match-string 2 arg1 ) ) )
( message " Package is %s, subdir is %s " package subdir )
( let ( ( dir ( ros-package-dir package ) ) )
( if dir
( shell-process-cd ( concat dir " / " subdir ) )
( lwarn ' ( rosemacs ) :debug " Unable to find directory of ros package %s. " arg1 ) ) ) )
( let ( ( dir ( ros-package-dir arg1 ) ) )
( if dir
( shell-process-cd dir )
( lwarn ' ( rosemacs ) :debug " Unable to find directory of ros package %s. " arg1 ) ) ) ) ) )
;; TODO deal with popd
( setq start ( progn ( string-match shell-command-separator-regexp str end )
( match-end 0 ) ) ) ) ) )
( defun ros-emacs-current-word ( )
( save-excursion
( skip-syntax-backward " w_.() " )
( let ( ( start ( point ) ) )
( skip-syntax-forward " w_.() " )
( buffer-substring-no-properties start ( point ) ) ) ) )
( defun ros-emacs-last-word ( )
( let ( ( end ( point ) ) )
( skip-syntax-backward " w_.() " )
( buffer-substring-no-properties ( point ) end ) ) )
2009-09-17 06:51:14 +08:00
2009-09-11 11:08:16 +08:00
( defvar *ros-commands-starting-with-package* ' ( " roscd " " rosmake " " rosrun " " rospd " ) )
( defun comint-get-ros-package-prefix ( )
( ros-command-prefix *ros-commands-starting-with-package* ) )
( defun ros-command-prefix ( commands )
( save-excursion
( block match-block
( let ( ( arg ( ros-emacs-last-word ) ) )
( skip-syntax-backward " " )
( dolist ( cmd commands nil )
( when ( string-equal cmd ( buffer-substring-no-properties ( - ( point ) ( length cmd ) ) ( point ) ) )
( return-from match-block arg ) ) ) ) ) ) )
( defun comint-get-ros-topic-prefix ( )
( save-excursion
( let ( ( arg ( ros-emacs-last-word ) ) )
( skip-syntax-backward " " )
( ros-emacs-last-word )
( skip-syntax-backward " " )
( let ( ( start ( - ( point ) 8 ) ) )
( when ( and ( >= start 0 ) ( string-equal " rostopic " ( buffer-substring-no-properties start ( point ) ) ) )
arg ) ) ) ) )
2010-07-13 06:08:36 +08:00
( defun comint-get-ros-node-prefix ( )
( save-excursion
( let ( ( arg ( ros-emacs-last-word ) ) )
( skip-syntax-backward " " )
( ros-emacs-last-word )
( skip-syntax-backward " " )
( let ( ( start ( - ( point ) 7 ) ) )
( when ( and ( >= start 0 ) ( string-equal " rosnode " ( buffer-substring-no-properties start ( point ) ) ) )
arg ) ) ) ) )
2009-12-10 02:11:20 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; rosrun
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defvar ros-run-temp-var " " )
( defvar ros-run-exec-names nil )
( defun extract-exec-name ( path )
( string-match " \\ ([^ \/ ]+ \\ )$ " path )
( match-string 1 path ) )
2010-07-11 11:59:23 +08:00
2009-12-10 02:11:20 +08:00
( defun ros-find-executables ( pkg )
( let ( ( ros-run-exec-paths nil )
( path ( ros-package-path pkg ) ) )
( save-excursion
( with-temp-buffer
( call-process " find " nil t nil path " -perm " " -100 " " ! " " -type " " d " )
( goto-char ( point-min ) )
( loop
( let ( ( pos ( re-search-forward " ^ \\ (.+ \\ )$ " ( point-max ) t ) ) )
( if pos
( let ( ( str ( match-string 1 ) ) )
( push str ros-run-exec-paths ) )
( return ) ) ) ) ) )
( sort* ( map 'vector 'extract-exec-name ros-run-exec-paths ) 'string< ) ) )
2010-07-11 11:59:23 +08:00
2009-12-10 02:11:20 +08:00
( defun ros-package-path ( pkg )
( save-excursion
2010-07-11 11:59:23 +08:00
( with-temp-buffer
( call-process " rospack " nil t nil " find " pkg )
( goto-char ( point-min ) )
( re-search-forward " ^ \\ (.* \\ )$ " )
( match-string 1 ) ) ) )
2009-12-10 02:11:20 +08:00
( define-minor-mode ros-run-mode
" Mode used for rosrun
k kills the process ( sends SIGINT ) .
q kills the buffer and process. "
:init-value nil
:lighter " ros-run "
:keymap ros-topic-echo-keymap
( message " ros-run mode: k to stop, q to quit " ) )
2010-07-08 14:20:27 +08:00
( defun rosemacs/contains-running-process ( name )
( let ( ( buf ( get-buffer name ) ) )
( and buf
( let ( ( proc ( get-buffer-process buf ) ) )
( and proc
( member ( process-status proc ) ' ( run stop ) ) ) ) ) ) )
2010-07-03 02:23:00 +08:00
2009-12-10 02:11:20 +08:00
( defun ros-run ( pkg exec &rest args )
" pkg is a ros package name and exec is the executable name. Tab completes package name. Exec defaults to package name itself. "
2010-04-26 09:41:36 +08:00
( interactive ( list ( setq ros-run-temp-var ( ros-completing-read-package
2010-05-20 05:51:26 +08:00
nil ( get-buffer-ros-package ) ) )
2010-04-26 09:41:36 +08:00
( funcall ros-completion-function ( format " Enter executable (default %s): " ros-run-temp-var )
( mapcar ( lambda ( pkg )
( cons pkg nil ) )
( ros-find-executables ros-run-temp-var ) )
nil nil nil nil ros-run-temp-var ) ) )
2010-07-08 14:20:27 +08:00
( let ( ( name ( format " *rosrun:%s/%s " pkg exec ) ) )
( if ( rosemacs/contains-running-process name )
( warn " Rosrun buffer %s already exists: not creating a new one. " name )
( let ( ( buf ( get-buffer-create name ) ) )
( apply #' start-process name buf " rosrun " pkg exec args )
( save-excursion
( set-buffer buf )
( view-buffer-other-window buf )
( ros-run-mode 1 ) )
buf ) ) ) )
2009-12-10 02:11:20 +08:00
2010-07-03 02:23:00 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; roslaunch
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2010-07-11 11:59:23 +08:00
( defvar ros-launch-path nil " The path to the file being launched " )
( make-variable-buffer-local 'ros-launch-path )
( defvar ros-launch-filename nil " The file being launched " )
( make-variable-buffer-local 'ros-launch-filename )
2010-07-08 14:20:27 +08:00
2010-07-03 02:23:00 +08:00
( defun ros-launch ( package-name )
2010-07-11 11:59:23 +08:00
" Open up the directory corresponding to PACKAGE-NAME in dired mode. If used interactively, tab completion will work. " ( interactive ( list ( ros-completing-read-pkg-file " Enter ros path: " ) ) )
2010-07-03 02:23:00 +08:00
( multiple-value-bind ( package dir-prefix dir-suffix ) ( parse-ros-file-prefix package-name )
( let* ( ( package-dir ( ros-package-dir package ) )
( path ( if dir-prefix ( concat package-dir dir-prefix dir-suffix ) package-dir ) ) )
( if path
2010-07-08 14:20:27 +08:00
( let ( ( name ( format " roslaunch:%s/%s " package dir-suffix ) ) )
( if ( rosemacs/contains-running-process name )
( warn " Roslaunch buffer %s already exists: not creating a new one. " name )
( let ( ( buf ( get-buffer-create name ) ) )
( save-excursion
( set-buffer buf )
2010-07-11 11:59:23 +08:00
( setq ros-launch-path path )
( setq ros-launch-filename dir-suffix )
( ros-launch-mode 1 )
( rosemacs/relaunch ( current-buffer ) ) )
2010-07-13 06:08:36 +08:00
( display-buffer buf )
2010-07-08 14:20:27 +08:00
buf ) ) )
2010-07-03 02:23:00 +08:00
( error " Did not find %s in the ros package list. " package-name ) ) ) ) )
2010-07-11 11:59:23 +08:00
2010-07-08 14:20:27 +08:00
( defun rosemacs/relaunch ( buf )
( let ( ( proc ( get-buffer-process buf ) ) )
( if ( and proc ( eq ( process-status proc ) 'run ) )
( warn " Can't relaunch since process %s is still running " proc )
( save-excursion
( set-buffer buf )
2010-07-13 06:08:36 +08:00
( start-process ( buffer-name buf ) buf " roslaunch " ros-launch-path )
( rosemacs/add-event ( format " %s: Ros launch of %s \n " ( float-time ) ros-launch-path ) )
)
) ) )
2010-07-08 14:20:27 +08:00
( defun rosemacs/relaunch-current-process ( )
( interactive )
( rosemacs/relaunch ( current-buffer ) ) )
2010-07-03 02:23:00 +08:00
( defvar ros-launch-keymap ( make-sparse-keymap ) )
2010-07-11 11:59:23 +08:00
( define-key ros-launch-keymap " k " 'rosemacs/interrupt-process )
2010-07-08 14:20:27 +08:00
( define-key ros-launch-keymap " q " 'kill-current-buffer )
( define-key ros-launch-keymap " r " 'rosemacs/relaunch-current-process )
2010-07-03 02:23:00 +08:00
2010-07-13 06:08:36 +08:00
2010-07-03 02:23:00 +08:00
( define-minor-mode ros-launch-mode
" Mode used for roslaunch
k kills the process ( sends SIGINT ) "
:init-value nil
:lighter " ros-launch "
:keymap ros-launch-keymap
)
2010-07-13 06:08:36 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Event buffer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defun rosemacs/add-event ( str &optional display-in-minibuffer )
( save-excursion
( when display-in-minibuffer ( message str ) )
( set-buffer ros-events-buffer )
( goto-char ( point-max ) )
( terpri ros-events-buffer )
( insert str )
)
)
( defun rosemacs/display-event-buffer ( )
( interactive )
( display-buffer ros-events-buffer ) )
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Keymap
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defvar ros-keymap ( make-sparse-keymap ) )
( define-key ros-keymap " \C -f " 'find-ros-file )
( define-key ros-keymap " f " 'view-ros-file )
( define-key ros-keymap " \C -m " 'find-ros-message )
( define-key ros-keymap " m " 'view-ros-message )
( define-key ros-keymap " \C -s " 'find-ros-service )
( define-key ros-keymap " s " 'view-ros-service )
2010-07-03 02:23:00 +08:00
( define-key ros-keymap " \C -r " 'ros-run )
( define-key ros-keymap " r " 'ros-load-package-locations )
2009-09-11 11:08:16 +08:00
( define-key ros-keymap " \C -c " 'ros-core )
( define-key ros-keymap " \C -t " 'display-ros-topic-info )
( define-key ros-keymap " t " 'echo-ros-topic )
( define-key ros-keymap " h " 'add-hz-update )
( define-key ros-keymap " H " 'remove-hz-update )
2009-09-17 06:51:14 +08:00
( define-key ros-keymap " T " 'ros-topic-info )
2010-05-20 05:51:26 +08:00
( define-key ros-keymap " g " 'ros-rgrep-package )
2010-07-03 02:23:00 +08:00
( define-key ros-keymap " \C -l " 'ros-launch )
2010-07-13 06:08:36 +08:00
( define-key ros-keymap " \C -e " 'rosemacs/display-event-buffer )
( define-key ros-keymap " \C -n " 'rosemacs/display-nodes )
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Invoking the mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defun set-rosemacs-shell-hooks ( )
( add-hook 'comint-input-filter-functions 'ros-directory-tracker nil t )
( add-hook 'comint-dynamic-complete-functions 'comint-dynamic-complete-ros-package nil t )
2010-07-13 06:08:36 +08:00
( add-hook 'comint-dynamic-complete-functions 'comint-dynamic-complete-ros-topic nil t )
( add-hook 'comint-dynamic-complete-functions 'comint-dynamic-complete-ros-node nil t ) )
2009-09-11 11:08:16 +08:00
( defun invoke-rosemacs ( )
( interactive )
( add-hook 'shell-mode-hook 'set-rosemacs-shell-hooks )
2010-07-13 06:08:36 +08:00
( setq rosemacs/invoked t )
2010-07-11 11:59:23 +08:00
( rosemacs/track-topics ros-topic-update-interval )
2010-07-13 06:08:36 +08:00
( rosemacs/track-nodes ros-node-update-interval )
2010-07-11 11:59:23 +08:00
)
2009-09-11 11:08:16 +08:00
2009-09-17 06:51:14 +08:00
2009-09-11 11:08:16 +08:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Internal
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2009-12-10 02:11:20 +08:00
( defun rosemacs-get-comp ( completions i )
2009-09-17 06:51:14 +08:00
( let ( ( comp ( aref completions i ) ) )
( string-match " ^/* \\ (.* \\ ) " comp )
( match-string 1 comp ) ) )
2009-09-11 11:08:16 +08:00
2009-12-10 02:11:20 +08:00
( defun rosemacs-bsearch ( str completions )
2009-09-11 11:08:16 +08:00
" str is a string, completions is a sorted vector of strings. Return list of strings in completions that str is a prefix of. "
( let ( ( num-completions ( length completions ) ) )
( unless ( or ( = num-completions 0 )
2009-12-10 02:11:20 +08:00
( string< ( rosemacs-get-comp completions ( 1- num-completions ) ) str ) )
2009-09-11 11:08:16 +08:00
( let ( ( i 0 )
( j ( 1- num-completions ) ) )
( while ( < ( 1+ i ) j )
( let ( ( k ( floor ( + i j ) 2 ) ) )
2009-12-10 02:11:20 +08:00
( if ( string< str ( rosemacs-get-comp completions k ) )
2009-09-11 11:08:16 +08:00
( setq j k )
( setq i k ) ) ) )
2009-12-10 02:11:20 +08:00
( when ( not ( rosemacs-is-prefix str ( rosemacs-get-comp completions i ) ) )
2009-09-11 11:08:16 +08:00
( incf i ) )
;; Postcondition: completions of str, if they exist, begin at i
( let ( ( returned-completions nil ) )
2009-12-10 02:11:20 +08:00
( while ( and ( < i ( length completions ) ) ( rosemacs-is-prefix str ( rosemacs-get-comp completions i ) ) )
( push ( rosemacs-get-comp completions i ) returned-completions )
2009-09-11 11:08:16 +08:00
( incf i ) )
returned-completions ) ) ) ) )
2009-12-10 02:11:20 +08:00
( defun rosemacs-is-prefix ( str1 str2 )
2009-09-11 11:08:16 +08:00
( let ( ( m ( length str1 ) ) )
( eq t ( compare-strings str1 0 m str2 0 m ) ) ) )
2009-12-10 02:11:20 +08:00
( defun rosemacs-lookup-vectors ( str v1 v2 )
2009-09-11 11:08:16 +08:00
( let ( ( i ( position str v1 :test #' string-equal ) ) )
( when i
( aref v2 i ) ) ) )
2009-12-10 02:11:20 +08:00
( defun rosemacs-list-diffs ( l1 l2 )
2009-09-11 11:08:16 +08:00
" Given two sorted lists of strings, return a list with 1) l2 - l1 2) l1 - l2 "
( let ( ( added nil ) ( deleted nil ) ( remaining1 l1 ) ( remaining2 l2 ) )
( while ( or remaining1 remaining2 )
( cond
( ( or ( null remaining1 ) ( and remaining2 ( string< ( car remaining2 ) ( car remaining1 ) ) ) )
( push ( car remaining2 ) added )
( setq remaining2 ( cdr remaining2 ) ) )
( ( or ( null remaining2 ) ( and remaining1 ( string< ( car remaining1 ) ( car remaining2 ) ) ) )
( push ( car remaining1 ) deleted )
( setq remaining1 ( cdr remaining1 ) ) )
( t ( setq remaining1 ( cdr remaining1 )
remaining2 ( cdr remaining2 ) ) ) ) )
( lwarn ' ( rosemacs ) :debug " Diffs of %s and %s are %s and %s " l1 l2 added deleted )
( list added deleted ) ) )
2010-07-13 06:08:36 +08:00
( defun set-ros-topic-update-interval ( n )
( warn " The function set-ros-topic-update-interval is deprecated; please check the wiki/instructions for how to track topics (summary: it happens by default, and you can customize ros-topic-update-interval to change the frequency, so you just need to remove the set-ros-topic-update-interval call from your .emacs) " )
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Parameters
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( defgroup rosemacs nil
" Customizations for rosemacs "
:group 'external )
( defcustom ros-completion-function 'completing-read
" The completion function to be used for package
completions. This variable can be set to ` ido-completing-read '
to enable ` ido-mode ' for ros packages. "
:type 'function
:group 'rosemacs )
( defcustom ros-topic-update-interval 8
" How often (seconds) to poll the list of ros topics. 0 means never. "
:type 'integer
:group 'rosemacs
:require 'rosemacs
:set #' ( lambda ( s val )
( set-default s val )
( when rosemacs/invoked
( rosemacs/track-topics val ) ) )
)
( defcustom ros-node-update-interval 8
" How often (seconds) to poll the list of ros nodes. 0 means never. "
:type 'integer
:group 'rosemacs
:require 'rosemacs
:set #' ( lambda ( s val )
( set-default s val )
( when rosemacs/invoked
( rosemacs/track-nodes val ) ) )
)
( defvar ros-topic-timeout-rate 5 " Number of seconds before info from rostopic hz is considered out-of-date " )
2009-09-11 11:08:16 +08:00
2010-07-20 14:10:57 +08:00
( provide 'rosemacs )
;;; rosemacs.el ends here