;** 
;**		BRIEF -- Basic Reconfigurable Interactive Editing Facility
;**
;**		Written by Dave Nanian and Michael Strickman.
;**
;**		Revision history:
;**		-----------------
;**		27 November 1985		Fixed bug in _buf_write: wasn't resetting the
;**									buffer list buffer in some cases.
;**
;**		6 October 1985			Changed temporary buffers to remove filenames.
;**									Revised display to include "*" after modified
;**									buffer names.  Implemented write option for
;**									modified buffers.
;**

;**
;**		buf_list.m:
;**
;**		This macro provides the user with a list of buffers that can be
;**	manipulated and scrolled through.  It is of interest because it
;**	simulates an array of buffer ids using a system buffer.  Macro
;**	programmers interested in using arrays should examine this code
;**	carefully before implementing an array system of their own.
;**

#define	SYSTEM	1						;** The value to use for system buffers.
#define	NEW_FILE	1						;** The value to use for new file attachments.

(macro buf_list
	(
		(int			_buf_list			;** Buffer that contains visible list.
						_buf_array			;** Buffer that simulates an array.
						_buf_end				;** The buffer to be attached on exit.
						num_bufs				;** The number of buffers in the list.
						start_buf			;** The buffer we started on.
						curr_buf				;** The buffer we're on (in the loop).
						modified				;** Is the current buffer modified?
		)
		(string		file_name			;** The file name of the buffer.
						buffer_name			;** The buffer name.
						file_line			;** Buffer for line to insert.
		)
		(global		_buf_list
						_buf_array
						_buf_end
		)

;**
;**		First, we create the array and list buffers, making sure that they
;**	have the "system" attributes.  We use non-file buffers because this is
;**	temporary information.
;**
;**		The "_buf_list" buffer contains a textual list of all of the non
;**	system buffers currently in memory.  "_buf_array" contains a list of the
;**	corresponding buffer pointers.  Note that the buffer pointers are not
;**	inserted into the buffer as is -- they are converted to string integers
;**	first.  This prevents inserting bad characters like tab, return and EOF.
;**

		(message "Creating buffer list...")

		;**		First, we get the ID of the current buffer -- we have to
		;**	restore it at the end of the macro.  After that, we create the
		;**	array buffer and put it aside for the moment.

		(= start_buf (= _buf_end (inq_buffer)))
		(= _buf_array (create_buffer "Buffer Array" NULL SYSTEM))

		;**		Now, we create the buffer that the user will actually see on
		;**	the screen, set it to be the current buffer, and set the tabs to
		;**	the values we want (tabs default to every column).

		(= _buf_list (create_buffer "Buffer List" NULL SYSTEM))
		(set_buffer _buf_list)
		(tabs 5)

		;**		This loop creates both buffer lists:  the non-system buffers
		;**	are looped through and information about them are culled and added
		;**	to the list.

		(while (!= start_buf curr_buf)
			(
				(if (! curr_buf)
					(= curr_buf start_buf)
				;else
					(
						(set_buffer _buf_list)
						(insert "\n")
						(set_buffer _buf_array)
						(insert "\n")
					)
				)
				(++ num_bufs)
				(set_buffer curr_buf)
				(inq_names file_name NULL buffer_name)
				(= modified (inq_modified))
				(set_buffer _buf_list)
				(sprintf file_line "%d)\tBuffer \"%s\" has " num_bufs buffer_name)
				(insert file_line)

				(if (! modified)
					(insert "not ")
				)
				(insert "been modified.\n\tFile: ")
				(insert file_name)

				(if modified
					(insert "*")
				)
				(set_buffer _buf_array)
				(sprintf file_line "%d" curr_buf)
				(insert file_line)
				(set_buffer curr_buf)
				(= curr_buf (next_buffer))
			)
		)
		(message "List created.")

;**
;**		At this point, the array buffer and list buffer have been created
;**	and filled in.  We create a window to display the list in, initialize
;**	the marked area, set up a keymap, and call process.  Process handles
;**	the mainline loop -- we need only provide action routines.
;**

		(create_window 5 17 74 4 " or  to select, E to edit, D to delete, W to write, ESC to exit.")
		(attach_buffer _buf_list)

		(keyboard_push)
		(assign_to_key "%P" "_buf_down")
		(assign_to_key "%H" "_buf_up")
		(assign_to_key "d" "_buf_delete")
		(assign_to_key "D" "_buf_delete")
		(assign_to_key "e" "_buf_edit")
		(assign_to_key "E" "_buf_edit")
		(assign_to_key "W" "_buf_write")
		(assign_to_key "w" "_buf_write")
		(assign_to_key "#13" "_buf_edit")
		(assign_to_key "#27" "exit")

		(move_abs 2 100)
		(drop_anchor)
		(move_abs 1 1)
		(set_buffer _buf_array)
		(move_abs 1 1)
		(set_buffer _buf_list)
		(refresh)

		(process)

		;**		Now that we're back from the processing, we pop the keymap that
		;**	we created, raise the assorted anchors, and delete the temporary
		;**	window and the buffers.

		(keyboard_pop)
		(raise_anchor)
		(delete_window)
		(delete_buffer _buf_list)
		(delete_buffer _buf_array)

		;**		If we end with a different buffer than we started with, we
		;**	attach it to the current window and display its file name.
		;**	Otherwise, we set the current buffer back, and call REG_NEW_FILE
		;**	to make sure its defaults are reset.

		(if (!= start_buf _buf_end)
			(
				(attach_buffer _buf_end)
				(display_file_name)
			)
		;else
			(
				(set_buffer start_buf)
				(call_registered_macro NEW_FILE)
				(message "")
			)
		)
	)
)

;**
;**		_buf_down:
;**
;**		This routine is called whenever the user presses a down arrow.
;**	It moves the array buffer and list buffer's current lines, ensuring
;**	the user does not go past the end of the buffer.
;**

(macro _buf_down
	(
		(int			line
						col
		)
		(move_rel 3 100)

		(if (inq_position line col)
			(move_rel -3 -100)
		;else
			(
				(raise_anchor)
				(drop_anchor)
				(move_rel -1 -100)
				(set_buffer _buf_array)
				(move_rel 1 0)
				(set_buffer _buf_list)
			)
		)
	)
)

;**
;**		_buf_up:
;**
;**		This macro is called whenever the user presses the up arrow.  It
;**	moves up in the list and array buffers, not going past the top of the
;**	buffer.
;**

(macro _buf_up
	(
		(int			line
						col
		)
		(inq_position line col)

		(if (> line 1)
			(
				(move_rel -1 100)
				(raise_anchor)
				(drop_anchor)
				(move_rel -1 -100)
				(set_buffer _buf_array)
				(move_rel -1 0)
				(set_buffer _buf_list)
			)
		)
	)
)

;**
;**		_buf_delete:
;**
;**		This routine is called when the user wants to delete a buffer.
;**	It makes sure the buffer is not in a window, and prompts the user
;**	if the buffer has been modified.
;**

(macro _buf_delete
	(
		(int		buf_to_delete
					line
					col
		)
		(string	misc_str)

		(set_buffer	_buf_array)
		(= buf_to_delete (atoi (read)))
		(set_buffer buf_to_delete)
		(= misc_str "y")

		(if (! (inq_views))
			(
				(if (inq_modified)
					(
						(keyboard_flush)

						(if (! (get_parm NULL misc_str "Buffer is modified: are you sure? " 1))
							(= misc_str "n")
						)
					)
				)
				(if (index "yY" misc_str)
					(
						(set_buffer _buf_list)
						(delete_line)
						(delete_line)
						(set_buffer _buf_array)
						(delete_line)
						(delete_buffer buf_to_delete)
						(set_buffer _buf_list)

						(if (inq_position line col)
							(_buf_up)
						;else
							(
								(raise_anchor)
								(move_rel 1 100)
								(drop_anchor)
								(move_rel -1 -100)
							)
						)
					)
				;else
					(message "Buffer not deleted.")
				)
			)
		;else
			(error "You can't delete a viewed buffer.")
		)
		(set_buffer _buf_list)
	)
)

;**		_buf_edit:
;**
;**		This routine is called when the user is on a buffer that he wants
;**	to edit.  It sets the global "_buf_end" variable to the current
;**	line's buffer, and calls exit so no further processing takes place.
;**

(macro _buf_edit
	(
		(set_buffer _buf_array)
		(= _buf_end (atoi (read)))
		(set_buffer _buf_list)
		(exit)
	)
)

;**
;**		_buf_write:
;**
;**		This routine is called when the user wants to write a modified
;**	buffer.  It makes sure the buffer is modified -- if so, it's written
;**	and the information in the window is updated.
;**

(macro _buf_write
	(
		(int		old_msg_level)

		(set_buffer	_buf_array)
		(set_buffer (atoi (read)))

		(if (inq_modified)
			(
				(= old_msg_level (inq_msg_level))
				(set_msg_level 0)

				(if (>= (write_buffer) 0)
					(
						(set_msg_level old_msg_level)
						(set_buffer _buf_list)
						(search_fwd "has \\c")
						(insert "not ")
						(down)
						(end_of_line)
						(backspace)
						(move_rel -1 -100)
					)
				;else
					(set_msg_level old_msg_level)
				)
			)
		;else
			(error "Buffer not modified.")
		)
		(set_buffer _buf_list)
	)
)
