Exemplo n.º 1
0
Arquivo: ui.c Projeto: roxma/neovim
static void remote_ui_default_colors_set(UI *ui, Integer rgb_fg,
                                         Integer rgb_bg, Integer rgb_sp,
                                         Integer cterm_fg, Integer cterm_bg)
{
  Array args = ARRAY_DICT_INIT;
  ADD(args, INTEGER_OBJ(rgb_fg));
  ADD(args, INTEGER_OBJ(rgb_bg));
  ADD(args, INTEGER_OBJ(rgb_sp));
  ADD(args, INTEGER_OBJ(cterm_fg));
  ADD(args, INTEGER_OBJ(cterm_bg));
  push_call(ui, "default_colors_set", args);

  // Deprecated
  if (!ui->ui_ext[kUILinegrid]) {
    args = (Array)ARRAY_DICT_INIT;
    ADD(args, INTEGER_OBJ(ui->rgb ? rgb_fg : cterm_fg - 1));
    push_call(ui, "update_fg", args);

    args = (Array)ARRAY_DICT_INIT;
    ADD(args, INTEGER_OBJ(ui->rgb ? rgb_bg : cterm_bg - 1));
    push_call(ui, "update_bg", args);

    args = (Array)ARRAY_DICT_INIT;
    ADD(args, INTEGER_OBJ(ui->rgb ? rgb_sp : -1));
    push_call(ui, "update_sp", args);
  }
}
Exemplo n.º 2
0
Arquivo: ui.c Projeto: fatbird/neovim
static void remote_ui_put(UI *ui, uint8_t *data, size_t size)
{
  Array args = ARRAY_DICT_INIT;
  String str = { .data = xmemdupz(data, size), .size = size };
  ADD(args, STRING_OBJ(str));
  push_call(ui, "put", args);
}

static void remote_ui_bell(UI *ui)
{
  Array args = ARRAY_DICT_INIT;
  push_call(ui, "bell", args);
}
Exemplo n.º 3
0
Arquivo: ui.c Projeto: fatbird/neovim
static void remote_ui_resize(UI *ui, int width, int height)
{
  Array args = ARRAY_DICT_INIT;
  ADD(args, INTEGER_OBJ(width));
  ADD(args, INTEGER_OBJ(height));
  push_call(ui, "resize", args);
}
Exemplo n.º 4
0
Arquivo: ui.c Projeto: fatbird/neovim
static void remote_ui_cursor_goto(UI *ui, int row, int col)
{
  Array args = ARRAY_DICT_INIT;
  ADD(args, INTEGER_OBJ(row));
  ADD(args, INTEGER_OBJ(col));
  push_call(ui, "cursor_goto", args);
}
Exemplo n.º 5
0
Arquivo: ui.c Projeto: roxma/neovim
static void remote_ui_put(UI *ui, const char *cell)
{
  UIData *data = ui->data;
  data->client_col++;
  Array args = ARRAY_DICT_INIT;
  ADD(args, STRING_OBJ(cstr_to_string(cell)));
  push_call(ui, "put", args);
}
Exemplo n.º 6
0
Arquivo: ui.c Projeto: roxma/neovim
static void remote_ui_grid_clear(UI *ui, Integer grid)
{
  Array args = ARRAY_DICT_INIT;
  if (ui->ui_ext[kUILinegrid]) {
    ADD(args, INTEGER_OBJ(grid));
  }
  const char *name = ui->ui_ext[kUILinegrid] ? "grid_clear" : "clear";
  push_call(ui, name, args);
}
Exemplo n.º 7
0
Arquivo: ui.c Projeto: fatbird/neovim
static void remote_ui_set_scroll_region(UI *ui, int top, int bot, int left,
                                        int right)
{
  Array args = ARRAY_DICT_INIT;
  ADD(args, INTEGER_OBJ(top));
  ADD(args, INTEGER_OBJ(bot));
  ADD(args, INTEGER_OBJ(left));
  ADD(args, INTEGER_OBJ(right));
  push_call(ui, "set_scroll_region", args);
}
Exemplo n.º 8
0
struct session *connect_session(struct session *ses)
{
	int sock;

	push_call("connection_session(%p)",ses);

	ses->connect_retry = utime() + gts->connect_retry;

	reconnect:

	sock = connect_mud(ses, ses->host, ses->port);

	if (sock == -1)
	{
		cleanup_session(ses);

		pop_call();
		return NULL;
	}

	if (sock)
	{
		gtd->ses    = ses;
		ses->socket = sock;

		ses->connect_retry = 0;

		SET_BIT(ses->flags, SES_FLAG_CONNECTED);

		tintin_printf2(ses, "");

		tintin_printf(ses, "#SESSION '%s' CONNECTED TO '%s' PORT '%s'", ses->name, ses->host, ses->port);

		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "SESSION CONNECTED", ses->name, ses->host, ses->ip, ses->port);

		pop_call();
		return ses;
	}

	if (ses->connect_retry > utime())
	{
		goto reconnect;
	}

	if (ses->connect_error)
	{
		tintin_printf(ses, "#SESSION '%s' FAILED TO CONNECT.", ses->name);
	}

	cleanup_session(ses);

	pop_call();
	return NULL;
}
Exemplo n.º 9
0
Arquivo: ui.c Projeto: roxma/neovim
static void remote_ui_flush(UI *ui)
{
  UIData *data = ui->data;
  if (data->buffer.size > 0) {
    if (!ui->ui_ext[kUILinegrid]) {
      remote_ui_cursor_goto(ui, data->cursor_row, data->cursor_col);
    }
    push_call(ui, "flush", (Array)ARRAY_DICT_INIT);
    rpc_send_event(data->channel_id, "redraw", data->buffer);
    data->buffer = (Array)ARRAY_DICT_INIT;
  }
}
Exemplo n.º 10
0
Arquivo: ui.c Projeto: roxma/neovim
static void remote_ui_grid_resize(UI *ui, Integer grid,
                                  Integer width, Integer height)
{
  Array args = ARRAY_DICT_INIT;
  if (ui->ui_ext[kUILinegrid]) {
    ADD(args, INTEGER_OBJ(grid));
  }
  ADD(args, INTEGER_OBJ(width));
  ADD(args, INTEGER_OBJ(height));
  const char *name = ui->ui_ext[kUILinegrid] ? "grid_resize" : "resize";
  push_call(ui, name, args);
}
Exemplo n.º 11
0
void do_one_line(char *line, struct session *ses)
{
	char strip[BUFFER_SIZE];

	push_call("[%s] do_one_line(%s)",ses->name,line);

	if (HAS_BIT(ses->flags, SES_FLAG_IGNORELINE))
	{
		pop_call(); 
		return;
	}

	strip_vt102_codes(line, strip);

	if (!HAS_BIT(ses->list[LIST_ACTION]->flags, LIST_FLAG_IGNORE))
	{
		check_all_actions(ses, line, strip);
	}

	if (!HAS_BIT(ses->list[LIST_PROMPT]->flags, LIST_FLAG_IGNORE))
	{
		if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
		{
			check_all_prompts(ses, line, strip);
		}
	}

	if (!HAS_BIT(ses->list[LIST_GAG]->flags, LIST_FLAG_IGNORE))
	{
		check_all_gags(ses, line, strip);
	}

	if (!HAS_BIT(ses->list[LIST_SUBSTITUTE]->flags, LIST_FLAG_IGNORE))
	{
		check_all_substitutions(ses, line, strip);
	}

	if (!HAS_BIT(ses->list[LIST_HIGHLIGHT]->flags, LIST_FLAG_IGNORE))
	{
		check_all_highlights(ses, line, strip);
	}

	if (ses->logline)
	{
		logit(ses, line, ses->logline, TRUE);

		fclose(ses->logline);
		ses->logline = NULL;
	}

	pop_call();
	return;
}
Exemplo n.º 12
0
Arquivo: ui.c Projeto: roxma/neovim
static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed)
{
  if (!ui->ui_ext[kUILinegrid]) {
    // the representation of highlights in cmdline changed, translate back
    // never consumes args
    if (strequal(name, "cmdline_show")) {
      Array new_args = translate_firstarg(ui, args);
      push_call(ui, name, new_args);
      return;
    } else if (strequal(name, "cmdline_block_show")) {
      Array new_args = ARRAY_DICT_INIT;
      Array block = args.items[0].data.array;
      Array new_block = ARRAY_DICT_INIT;
      for (size_t i = 0; i < block.size; i++) {
        ADD(new_block,
            ARRAY_OBJ(translate_contents(ui, block.items[i].data.array)));
      }
      ADD(new_args, ARRAY_OBJ(new_block));
      push_call(ui, name, new_args);
      return;
    } else if (strequal(name, "cmdline_block_append")) {
      Array new_args = translate_firstarg(ui, args);
      push_call(ui, name, new_args);
      return;
    }
  }

  Array my_args = ARRAY_DICT_INIT;
  // Objects are currently single-reference
  // make a copy, but only if necessary
  if (*args_consumed) {
    for (size_t i = 0; i < args.size; i++) {
      ADD(my_args, copy_object(args.items[i]));
    }
  } else {
    my_args = args;
    *args_consumed = true;
  }
  push_call(ui, name, my_args);
}
Exemplo n.º 13
0
Arquivo: ui.c Projeto: fatbird/neovim
static void remote_ui_mode_change(UI *ui, int mode)
{
  Array args = ARRAY_DICT_INIT;
  if (mode == INSERT) {
    ADD(args, STRING_OBJ(cstr_to_string("insert")));
  } else if (mode == REPLACE) {
    ADD(args, STRING_OBJ(cstr_to_string("replace")));
  } else {
    assert(mode == NORMAL);
    ADD(args, STRING_OBJ(cstr_to_string("normal")));
  }
  push_call(ui, "mode_change", args);
}
Exemplo n.º 14
0
Arquivo: ui.c Projeto: roxma/neovim
/// emulated cursor used both for drawing and for input focus
static void remote_ui_cursor_goto(UI *ui, Integer row, Integer col)
{
  UIData *data = ui->data;
  if (data->client_row == row && data->client_col == col) {
    return;
  }
  data->client_row = row;
  data->client_col = col;
  Array args = ARRAY_DICT_INIT;
  ADD(args, INTEGER_OBJ(row));
  ADD(args, INTEGER_OBJ(col));
  push_call(ui, "cursor_goto", args);
}
Exemplo n.º 15
0
void write_node(struct session *ses, int list, struct listnode *node, FILE *file)
{
	char result[STRING_SIZE], buffer[BUFFER_SIZE];

	int llen = UMAX(20, strlen(node->left));
	int rlen = UMAX(25, strlen(node->right));

	push_call("write_node(%d,%p,%p)",list,node,file);

	switch (list)
	{
		case LIST_EVENT:
		case LIST_FUNCTION:
		case LIST_MACRO:
			sprintf(result, "%c%s {%s}\n{\n%s\n}\n\n", gtd->command_char, list_table[list].name, node->left, script_writer(ses, node->right));
			break;

		case LIST_ACTION:
		case LIST_ALIAS:
			sprintf(result, "%c%s {%s}\n{\n%s\n}\n{%s}\n\n", gtd->command_char, list_table[list].name, node->left, script_writer(ses, node->right), node->pr);
			break;

		case LIST_VARIABLE:
			show_nest_node(node, buffer, 1);
			sprintf(result, "%c%-16s {%s} %*s {%s}\n", gtd->command_char, list_table[list].name, node->left, 20 - llen, "", buffer);
			break;

		default:

			switch (list_table[list].args)
			{
				case 0:
					result[0] = 0;
					break;
				case 1:
					sprintf(result, "%c%-16s {%s}\n", gtd->command_char, list_table[list].name, node->left);
					break;
				case 2:
					sprintf(result, "%c%-16s {%s} %*s {%s}\n", gtd->command_char, list_table[list].name, node->left, 20 - llen, "", node->right);
					break;
				case 3:
					sprintf(result, "%c%-16s {%s} %*s {%s} %*s {%s}\n", gtd->command_char, list_table[list].name, node->left, 20 - llen, "", node->right, 25 - rlen, "", node->pr);
					break;
			}
			break;
	}
	fputs(result, file);

	pop_call();
	return;
}
Exemplo n.º 16
0
Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, VARIANT_ARG_DECLARE) {

	VARIANT_ARGPTRS;

	int argc = 0;

	for (int i = 0; i < VARIANT_ARG_MAX; i++) {
		if (argptr[i]->get_type() == Variant::NIL)
			break;
		argc++;
	}

	return push_call(p_id, p_method, argptr, argc, false);
}
Exemplo n.º 17
0
void cleanup_session(struct session *ses)
{
	push_call("cleanup_session(%p)",ses);

	if (ses == gtd->update)
	{
		gtd->update = ses->next;
	}

	UNLINK(ses, gts->next, gts->prev);

	if (ses->socket)
	{
		if (close(ses->socket) == -1)
		{
			syserr("close in cleanup");
		}

		if (HAS_BIT(ses->flags, SES_FLAG_RUN))
		{
			kill(ses->pid, SIGKILL);
		}

		DEL_BIT(ses->flags, SES_FLAG_CONNECTED);
	}

	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 3, "SESSION DISCONNECTED", ses->name, ses->command, ntos(ses->pid));

	display_printf(gtd->ses, "#SESSION '%s' DIED.", ses->name);

	if (ses == gtd->ses)
	{
		gtd->ses = newactive_session();
	}

	if (ses->logfile)
	{
		fclose(ses->logfile);
	}

	if (ses->logline)
	{
		fclose(ses->logline);
	}

	LINK(ses, gtd->dispose_next, gtd->dispose_prev);

	pop_call();
	return;
}
Exemplo n.º 18
0
void init_buffer(struct session *ses, int size)
{
	int cnt;

	push_call("init_buffer(%p,%p)",ses,size);

	if (ses->scroll_max == size)
	{
		pop_call();
		return;
	}

	if (ses->buffer)
	{
		cnt = ses->scroll_row;
		
		do
		{
			if (++cnt == ses->scroll_max)
			{
				cnt = 0;
			}

			if (ses->buffer[cnt] == NULL)
			{
				break;
			}

			str_unhash(ses->buffer[cnt]);
		}
		while (cnt != ses->scroll_row);
	}

	if (ses->buffer)
	{
		free(ses->buffer);
	}

	if (size)
	{
		ses->buffer = (char **) calloc(size, sizeof(char *));

		ses->scroll_max  = size;
		ses->scroll_row  = size - 1;
		ses->scroll_line = - 1;
	}
	pop_call();
	return;
}
Exemplo n.º 19
0
void printline(struct session *ses, char **str, int prompt)
{
	char *out;

	push_call("printline(%p,%p,%d)",ses,*str,prompt);

	if (ses->scroll_line != -1 && HAS_BIT(ses->flags, SES_FLAG_SCROLLLOCK))
	{
		pop_call();
		return;
	}

	if (HAS_BIT(ses->flags, SES_FLAG_SCAN) && !HAS_BIT(ses->flags, SES_FLAG_VERBOSE))
	{
		pop_call();
		return;
	}

	out = str_alloc(strlen(*str) * 2);

	if (HAS_BIT(ses->flags, SES_FLAG_CONVERTMETA))
	{
		convert_meta(*str, out);
		str_cpy(str, out);
	}

	if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
	{
		word_wrap(ses, *str, out, TRUE);
	}
	else
	{
		strcpy(out, *str);
	}

	if (prompt)
	{
		printf("%s", out);
	}
	else
	{
		printf("%s\n", out);
	}

	str_free(out);

	pop_call();
	return;
}
Exemplo n.º 20
0
Arquivo: ui.c Projeto: roxma/neovim
static void remote_ui_highlight_set(UI *ui, int id)
{
  Array args = ARRAY_DICT_INIT;
  UIData *data = ui->data;


  if (data->hl_id == id) {
    return;
  }
  data->hl_id = id;
  Dictionary hl = hlattrs2dict(syn_attr2entry(id), ui->rgb);

  ADD(args, DICTIONARY_OBJ(hl));
  push_call(ui, "highlight_set", args);
}
Exemplo n.º 21
0
struct session *newactive_session(void)
{
	push_call("newactive_session(void)");

	if (gts->next)
	{
		activate_session(gts->next);
	}
	else
	{
		activate_session(gts);
	}
	pop_call();
	return gtd->ses;
}
Exemplo n.º 22
0
Arquivo: ui.c Projeto: fatbird/neovim
static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed)
{
  Array my_args = ARRAY_DICT_INIT;
  // Objects are currently single-reference
  // make a copy, but only if necessary
  if (*args_consumed) {
    for (size_t i = 0; i < args.size; i++) {
      ADD(my_args, copy_object(args.items[i]));
    }
  } else {
    my_args = args;
    *args_consumed = true;
  }
  push_call(ui, name, my_args);
}
Exemplo n.º 23
0
Arquivo: ui.c Projeto: roxma/neovim
static void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top,
                                  Integer bot, Integer left, Integer right,
                                  Integer rows, Integer cols)
{
  if (ui->ui_ext[kUILinegrid]) {
    Array args = ARRAY_DICT_INIT;
    ADD(args, INTEGER_OBJ(grid));
    ADD(args, INTEGER_OBJ(top));
    ADD(args, INTEGER_OBJ(bot));
    ADD(args, INTEGER_OBJ(left));
    ADD(args, INTEGER_OBJ(right));
    ADD(args, INTEGER_OBJ(rows));
    ADD(args, INTEGER_OBJ(cols));
    push_call(ui, "grid_scroll", args);
  } else {
    Array args = ARRAY_DICT_INIT;
    ADD(args, INTEGER_OBJ(top));
    ADD(args, INTEGER_OBJ(bot-1));
    ADD(args, INTEGER_OBJ(left));
    ADD(args, INTEGER_OBJ(right-1));
    push_call(ui, "set_scroll_region", args);

    args = (Array)ARRAY_DICT_INIT;
    ADD(args, INTEGER_OBJ(rows));
    push_call(ui, "scroll", args);

    // some clients have "clear" being affected by scroll region,
    // so reset it.
    args = (Array)ARRAY_DICT_INIT;
    ADD(args, INTEGER_OBJ(0));
    ADD(args, INTEGER_OBJ(ui->height-1));
    ADD(args, INTEGER_OBJ(0));
    ADD(args, INTEGER_OBJ(ui->width-1));
    push_call(ui, "set_scroll_region", args);
  }
}
Exemplo n.º 24
0
void do_one_line(char *line, struct session *ses)
{
	char strip[BUFFER_SIZE];

	push_call("[%s] do_one_line(%s)",ses->name,line);

	if (gtd->ignore_level)
	{
		pop_call();
		return;
	}

	strip_vt102_codes(line, strip);

	if (!HAS_BIT(ses->list[LIST_ACTION]->flags, LIST_FLAG_IGNORE))
	{
		check_all_actions(ses, line, strip);
	}

	if (!HAS_BIT(ses->list[LIST_PROMPT]->flags, LIST_FLAG_IGNORE))
	{
		check_all_prompts(ses, line, strip);
	}

	if (!HAS_BIT(ses->list[LIST_GAG]->flags, LIST_FLAG_IGNORE))
	{
		check_all_gags(ses, line, strip);
	}

	if (!HAS_BIT(ses->list[LIST_SUBSTITUTE]->flags, LIST_FLAG_IGNORE))
	{
		check_all_substitutions(ses, line, strip);
	}

	if (!HAS_BIT(ses->list[LIST_HIGHLIGHT]->flags, LIST_FLAG_IGNORE))
	{
		check_all_highlights(ses, line, strip);
	}

	if (HAS_BIT(ses->flags, SES_FLAG_LOGNEXT))
	{
		logit(ses, line, ses->lognext_file, TRUE);

		DEL_BIT(ses->flags, SES_FLAG_LOGNEXT);
	}
	pop_call();
	return;
}
Exemplo n.º 25
0
Arquivo: net.c Projeto: SlySven/tintin
void write_line_mud(struct session *ses, char *line, int size)
{
	static int retry;

	push_call("write_line_mud(%p,%p)",line,ses);

	if (ses == gts)
	{
		tintin_printf2(ses, "#NO SESSION ACTIVE. USE: %csession {name} {host} {port} TO START ONE.", gtd->tintin_char);

		pop_call();
		return;
	}

	if (!HAS_BIT(ses->flags, SES_FLAG_CONNECTED))
	{
		tintin_printf2(ses, "#THIS SESSION IS NOT CONNECTED.");

		pop_call();
		return;
	}

	if (write(ses->socket, line, size) == -1)
	{
		if (retry++ < 10)
		{
			usleep(100000);

			write_line_mud(ses, line, size);

			pop_call();
			return;
		}
		perror("write in write_line_mud");

		cleanup_session(ses);

		pop_call();
		return;
	}

	retry = 0;

	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "SEND OUTPUT", line);

	pop_call();
	return;
}
Exemplo n.º 26
0
Arquivo: core.c Projeto: rbryan/rplisp
void push_core_functions(){
	int i;
	for(i=0; core_functions[i] != NULL; i++){
		//vsp should be the start location of the function
		push_symbol(fn_names[i],vsp); 
		//push the function
		push_start();
		push_call(core_functions[i]);
		push_term();
		//vsp should now be the stack location just after the function.
		//This space should later be filled by the start of the users
		//program.
		exec_entry_pt = vsp;

	}
}
Exemplo n.º 27
0
Arquivo: ui.c Projeto: roxma/neovim
/// "true" cursor used only for input focus
static void remote_ui_grid_cursor_goto(UI *ui, Integer grid, Integer row,
                                       Integer col)
{
  if (ui->ui_ext[kUILinegrid]) {
    Array args = ARRAY_DICT_INIT;
    ADD(args, INTEGER_OBJ(grid));
    ADD(args, INTEGER_OBJ(row));
    ADD(args, INTEGER_OBJ(col));
    push_call(ui, "grid_cursor_goto", args);
  } else {
    UIData *data = ui->data;
    data->cursor_row = row;
    data->cursor_col = col;
    remote_ui_cursor_goto(ui, row, col);
  }
}
Exemplo n.º 28
0
int read_buffer_mud(struct session *ses) {
  unsigned char buffer[BUFFER_SIZE];
  int size;

  push_call("read_buffer_mud(%p)", ses);

  size = read(ses->socket, buffer, BUFFER_SIZE - 1);

  if (size <= 0) {
    pop_call();
    return FALSE;
  }

  ses->read_len = translate_telopts(ses, buffer, size);

  pop_call();
  return TRUE;
}
Exemplo n.º 29
0
Arquivo: ui.c Projeto: roxma/neovim
static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs,
                                     HlAttrs cterm_attrs, Array info)
{
  if (!ui->ui_ext[kUILinegrid]) {
    return;
  }
  Array args = ARRAY_DICT_INIT;

  ADD(args, INTEGER_OBJ(id));
  ADD(args, DICTIONARY_OBJ(hlattrs2dict(rgb_attrs, true)));
  ADD(args, DICTIONARY_OBJ(hlattrs2dict(cterm_attrs, false)));

  if (ui->ui_ext[kUIHlState]) {
    ADD(args, ARRAY_OBJ(copy_array(info)));
  } else {
    ADD(args, ARRAY_OBJ((Array)ARRAY_DICT_INIT));
  }

  push_call(ui, "hl_attr_define", args);
}
Exemplo n.º 30
0
Arquivo: ui.c Projeto: fatbird/neovim
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
{
  Array args = ARRAY_DICT_INIT;
  Dictionary hl = ARRAY_DICT_INIT;

  if (attrs.bold) {
    PUT(hl, "bold", BOOLEAN_OBJ(true));
  }

  if (attrs.underline) {
    PUT(hl, "underline", BOOLEAN_OBJ(true));
  }

  if (attrs.undercurl) {
    PUT(hl, "undercurl", BOOLEAN_OBJ(true));
  }

  if (attrs.italic) {
    PUT(hl, "italic", BOOLEAN_OBJ(true));
  }

  if (attrs.reverse) {
    PUT(hl, "reverse", BOOLEAN_OBJ(true));
  }

  if (attrs.foreground != -1) {
    PUT(hl, "foreground", INTEGER_OBJ(attrs.foreground));
  }

  if (attrs.background != -1) {
    PUT(hl, "background", INTEGER_OBJ(attrs.background));
  }

  if (attrs.special != -1) {
    PUT(hl, "special", INTEGER_OBJ(attrs.special));
  }

  ADD(args, DICTIONARY_OBJ(hl));
  push_call(ui, "highlight_set", args);
}