2

I have a function that gathers strings that looks like these:

  • Example #1:   :event:lawlist:HIGH:misc:

  • Example #2:  :LOW:

  • Example #3: :MEDIUM:task:george:

I created a monstrosity of a snippet that breaks the string down into various sub-components, adds text properties to each component, and then reconstructs the new string.

Q:  Is there a more sophisticated way to do this project?

(let* (
    new-list
    (string ":event:lawlist:HIGH:misc:")
    (lst (delete "" (split-string string ":")))
    (separator (propertize ":" 'face '(:foreground "cyan"))) )
  (dolist (e lst)
    (put-text-property 0 (length e) 'face
      (cond
        ((string= e "event")
          '(:foreground "red"))
        ((string= e "lawlist")
          '(:foreground "blue"))
        ((string= e "HIGH")
          '(:foreground "yellow"))
        (t
          'default))
      e)
    (push e new-list))
  (concat separator (mapconcat 'identity (reverse new-list) separator) separator))
lawlist
  • 19,106
  • 5
  • 38
  • 120
  • You don't show/describe the context (the project), so this question seems overly broad. For example, are you manipulating strings when you could be manipulating text in buffers? – Drew Jul 02 '16 at 22:25
  • Are you decorating org-mode tags? Can you use org-tag-faces for this? – erikstokes Jul 02 '16 at 22:36
  • @Drew -- I have a custom function that uses an approximate 23-component regexp to extract certain elements of an outline, which is used in a custom version of org-mode. Here is a link to an older version of the regexp and function that I am using http://stackoverflow.com/a/20960301/2112489 I would prefer to operate on strings, instead of the buffer for this particular project. I realize the popular method is to use (while (re-search-forward ...), but this project is different. – lawlist Jul 02 '16 at 22:44
  • @erickstokes -- yes, (org-font-lock-add-tag-faces (point-max)) is a means of accomplishing the end goal (but it is not an answer to this question). It operates on the buffer, as @Drew is suggesting. I haven't found an example in org-mode that operates on strings. My snippet works, but it's just not very fancy -- I thought perhaps there were a few functions that I am not aware of that permits walking a string with delimiters or regexp to add text properties. In fact, I'd be rather surprised if such a function does not exist already. – lawlist Jul 02 '16 at 22:59
  • 1
    Insert the string into a temporary buffer, search for delimiters and add properties, then retrieve the buffer contents as string. – wasamasa Jul 03 '16 at 07:06

1 Answers1

2

The following is an alternative (but similar) method as described in the question above to walk (loop through) a string and add text properties:

(defun walk-string+add-face (str)
  (loop with start = 0
        with regexp = "[a-zA-Z0-9]+"
        with substring = nil
        with result = nil
        with separator = (propertize ":" 'face '(:foreground "cyan"))
        while (string-match regexp str start)
        do (setq substring (match-string 0 str))
        do (put-text-property 0 (length substring) 'face
             (cond
               ((string= substring "event")
                 '(:foreground "red"))
               ((string= substring "lawlist")
                 '(:foreground "blue"))
               ((string= substring "HIGH")
                 '(:foreground "yellow"))
               (t
                 'default))
             substring)
        do (push substring result)
        do (setq start (match-end 0))
        finally return
          (concat
            separator
            (mapconcat 'identity (reverse result) separator)
            separator)))

The usage is as follows: (walk-string+add-face ":event:lawlist:HIGH:misc:")

lawlist
  • 19,106
  • 5
  • 38
  • 120