Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement local traverse get/set #74

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

sorpaas
Copy link
Contributor

@sorpaas sorpaas commented Jan 21, 2017

This pull requests enable local traverse get/set. In the traverse function, one can use (set #:local #t key val) to set a local value. The local value will be available across the specific part. This is useful to implement traverse information relating to a specific part.

@mflatt
Copy link
Member

mflatt commented Mar 3, 2017

I'm having trouble understanding the intent here. The intended way for information to be local is to use a tag prefix on a part, so that the information is available from the outside only via the prefix. A tag prefix does effect everything in the part, though, so I wonder whether that's an issue for the use that you have in mind.

Can you say how this would be used in contrast to tag prefixes, and maybe provide a sketch for the documentation?

@sorpaas
Copy link
Contributor Author

sorpaas commented Mar 4, 2017

This is mainly for a traverse-element or traverse-block used in a traverse phase. If I understand Scribble's code correctly, in a given traverse phase, no matter whether you have tag prefixes or not in a given part, the traverse information ti is shared across all parts passed together to a renderer as a part tree. So I think tag prefixes does not help in this case.

For me, the usage is this:

Still back to the org-mode alternative example. We have (task #:category c . t), that creates a task in a traverse element (which can later be read by agenda) together with a task category. This works good by itself. However, sometimes I don't want to type the same category all the time in a given section. I might want all tasks defined in a given section to automatically belong to some categories. Using local get/set, I can do:

(define (current-category c)
  (traverse-element
    (lambda (get set)
      (set #:local #t 'current-category c)
      '())))

And then read it from a task:

(define (task t)
  (traverse-element
    (lambda (get set)
      (lambda (get set)
        (get 'current-category)
        ;;; And do something else
))))

I also use this to set current-lang for documents that I write in different languages in different sections. Use local get/set, I can have a section that is written in English, and then a subsection that is written in Chinese, and then a subsubsection that is written in Lojban.

@section{An English Section}
@current-lang[:en]

@subsection{A Chinese Section}
@current-lang[:zh]

@subsubsection{A Lojban Section}
@current-lang[:jbo]

@mflatt
Copy link
Member

mflatt commented Mar 5, 2017

Thanks for the explanation. I had forgotten about traverse versus collect and how the traverse pass is meant to be global and involve a fixpoint in a way that doesn't work with the (preferred, in my view) collect and resolve passes.

It sounds like the kind of thing you want to do might be better served with the collect and resolve passes, instead, as illustrated below. Would that work?

(I'm not opposed to adding new things, but I'd like to make sure that we need them.)

Thanks!

#lang scribble/base
@(require scribble/core)

@(define (current-lang c)
   (collect-element
    #f
    '()
    (lambda (ci)
      (collect-put! ci '(current-category (prefixable)) c))))

@(define (task t)
   (delayed-element
    (lambda (r p ri)
      (list t (symbol->string (resolve-get p ri '(current-category (prefixable))))))
    (lambda () (list t "???"))
    (lambda () (list t "???"))))

@section[#:tag-prefix "en"]{An English Section}
@current-lang[':en]
@task{one}

@subsection[#:tag-prefix "cn"]{A Chinese Section}
@current-lang[':zh]
@task{two}

@subsubsection[#:tag-prefix "lbo"]{A Lojban Section}
@current-lang[':jbo]
@task{three}

@subsection{A Section Back to English}
@task{four}

@sorpaas
Copy link
Contributor Author

sorpaas commented Mar 6, 2017

@mflatt Unfortunately no, because I cannot be sure that a task, or an agenda would be in the last phase (i.e. they may also want to set some information in ti or ci or ri). For example, I have agendas that would send me push notification using a third party service through an HTTP call. Those notifications must be processed one phase after the agenda. So they cannot be in a delayed-element.

Right now I have many phases including pre, primary, secondary, post, post-notify. And I really don't know there's another way to do this besides putting them all in different traverse phases.

@mflatt
Copy link
Member

mflatt commented Mar 8, 2017

Ok, I think I understand why more context is useful during the traverse pass.

I'm not convinced that #:local is the right way to go, though. It seems like a better approach would be to reflect the enclosing parts in general, and then a traverse function could use that information to make its own local tables – possibly using not just the immediately enclosing part, but the list of all enclosing parts.

Concretely, the function wrapped by traverse-block or traverse-element might accept an optional third argument that is a list of enclosing parts. The traversal loop could accumulate that list as it goes and provide the list to any traversal callback that accepts three arguments.

Would that work for your purposes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants