I created many registers in my document like this, which lets me store vocabulary words, using \definevocabulary{word} and then call the list later with \placeregister[vocabulary]:

\defineregister[vocabulary][pagenumber=no, indicator=no, before=, n=1]

When I call the list, it prints all of the words. There are some situations where I just want a subset of the list to be displayed. For instance, some words are considered as high priority, and I need to just print those. Others might be tagged as "for 5th graders" or "for 6th graders", and I might need to list just one set of those, or a combination such as "for 5th graders and high priority".

The only solution I can think is to create many different registers, and add the words to the ones they fit in, but this seems an overly complex solution:


Does ConTeXt have any way to tag items going into a register, so that only items meeting specific criteria, sometimes multiple criteria, are listed?

2 Answers 2


Why not simply define multiple registers and merge them while displaying.

\defineregister[easyvocabulary][pagenumber=no, indicator=no, before=, n=1]
\defineregister[hardvocabulary][pagenumber=no, indicator=no, before=, n=1]

\subject{Both registers}

\subject{Easy words}

\subject{Hard words}


which gives

enter image description here


I put together a bit of a hack using tags. Essentially, the vocabulary contents you defined is stored in lua in structures.registers.collected.vocabulary.entries. I wasn't sure what parts of that table are safe to access or not so I created an external table which keeps track of the tags. Then, when you want to place particular tags, I backup the main vocabulary list, filter it, place it, and then restore it. The result is a bit dirty, but hopefully avoid complications with ConTeXt internals... Perhaps someone can correct me on this.

The full solution:

\defineregister[vocabulary][pagenumber=no, indicator=no, before=, n=1]

  userdata = userdata or {}
  userdata.tags = {}

  -- Table copy function from https://stackoverflow.com/questions/640642/how-do-you-copy-a-lua-table-by-value
  local function copy(obj, seen)
    if type(obj) ~= 'table' then return obj end
    if seen and seen[obj] then return seen[obj] end
    local s = seen or {}
    local res = setmetatable({}, getmetatable(obj))
    s[obj] = res
    for k, v in pairs(obj) do res[copy(k, s)] = copy(v, s) end
    return res

  -- Test for presence of tag
  local function isin(item, tags)
    for _, tag in ipairs(tags) do
      local inner = false
      for _, value in ipairs(userdata.tags[tag]) do
        if item == value then 
          inner = true
      if not inner then
        return false
    return true

  userdata.add_tags = function(item, s) 
    -- Split string
    local tags = lpeg.split(lpeg.patterns.spacer, s or "")
    for _,tag in pairs(tags) do
      userdata.tags[tag] = userdata.tags[tag] or {}
      table.insert(userdata.tags[tag], item)

  userdata.filter_items = function(s)
    local tags = lpeg.split(lpeg.patterns.spacer, s or "")

    -- Backup current vocabulary
    local vocabulary = structures.registers.collected.vocabulary.entries
    userdata.backup = copy(vocabulary)

    -- Filter only tags we want
    local n = #vocabulary
    -- Going backwards to not disrupt order
    for i = n, 1, -1 do
      if not isin(vocabulary[i].list[1][1], tags) then
        table.remove(vocabulary, i)

  userdata.restore_items = function()
    structures.registers.collected.vocabulary.entries = copy(userdata.backup)


  \ctxlua{userdata.add_tags([==[#1]==], [==[#2]==])}%

  \placeregister[vocabulary] %

    \definevocabulary{fish}{animal water}
    \definevocabulary{bear}{animal land}
    \definevocabulary{kelp}{plant water}
    \definevocabulary{apple}{plant land}



    Land plants:
    \placevocabulary{plant land}


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .