58 } |
58 } |
59 |
59 |
60 |
60 |
61 /* input command */ |
61 /* input command */ |
62 |
62 |
63 object Command |
63 type Command_Body = PartialFunction[(Context, Any), Any] |
64 { |
64 |
65 type T = PartialFunction[(Context, Any), Any] |
65 abstract class Command(val command_name: String) |
66 |
66 { |
67 private val table: Map[String, T] = |
67 def command_body: Command_Body |
68 Map( |
68 override def toString: String = command_name |
69 "help" -> { case (_, ()) => table.keySet.toList.sorted }, |
69 } |
70 "echo" -> { case (_, t) => t }, |
70 |
71 "shutdown" -> { case (context, ()) => context.server.shutdown() }, |
71 class Commands(commands: Command*) extends Isabelle_System.Service |
72 "cancel" -> |
72 { |
73 { case (context, Server_Commands.Cancel(args)) => context.cancel_task(args.task) }, |
73 def entries: List[Command] = commands.toList |
74 "session_build" -> |
74 } |
75 { case (context, Server_Commands.Session_Build(args)) => |
75 |
76 context.make_task(task => |
76 private lazy val command_table: Map[String, Command] = |
77 Server_Commands.Session_Build.command(args, progress = task.progress)._1) |
77 (Map.empty[String, Command] /: Isabelle_System.make_services(classOf[Commands]).flatMap(_.entries))( |
78 }, |
78 { case (cmds, cmd) => |
79 "session_start" -> |
79 val name = cmd.command_name |
80 { case (context, Server_Commands.Session_Start(args)) => |
80 if (cmds.isDefinedAt(name)) error("Duplicate Isabelle server command: " + quote(name)) |
81 context.make_task(task => |
81 else cmds + (name -> cmd) |
82 { |
82 }) |
83 val (res, entry) = |
|
84 Server_Commands.Session_Start.command( |
|
85 args, progress = task.progress, log = context.server.log) |
|
86 context.server.add_session(entry) |
|
87 res |
|
88 }) |
|
89 }, |
|
90 "session_stop" -> |
|
91 { case (context, Server_Commands.Session_Stop(id)) => |
|
92 context.make_task(_ => |
|
93 { |
|
94 val session = context.server.remove_session(id) |
|
95 Server_Commands.Session_Stop.command(session)._1 |
|
96 }) |
|
97 }, |
|
98 "use_theories" -> |
|
99 { case (context, Server_Commands.Use_Theories(args)) => |
|
100 context.make_task(task => |
|
101 { |
|
102 val session = context.server.the_session(args.session_id) |
|
103 Server_Commands.Use_Theories.command( |
|
104 args, session, id = task.id, progress = task.progress)._1 |
|
105 }) |
|
106 }, |
|
107 "purge_theories" -> |
|
108 { case (context, Server_Commands.Purge_Theories(args)) => |
|
109 val session = context.server.the_session(args.session_id) |
|
110 Server_Commands.Purge_Theories.command(args, session)._1 |
|
111 }) |
|
112 |
|
113 def unapply(name: String): Option[T] = table.get(name) |
|
114 } |
|
115 |
83 |
116 |
84 |
117 /* output reply */ |
85 /* output reply */ |
118 |
86 |
119 class Error(val message: String, val json: JSON.Object.T = JSON.Object.empty) |
87 class Error(val message: String, val json: JSON.Object.T = JSON.Object.empty) |
209 |
177 |
210 class Context private[Server](val server: Server, connection: Connection) |
178 class Context private[Server](val server: Server, connection: Connection) |
211 extends AutoCloseable |
179 extends AutoCloseable |
212 { |
180 { |
213 context => |
181 context => |
|
182 |
|
183 def command_list: List[String] = command_table.keys.toList.sorted |
214 |
184 |
215 def reply(r: Reply.Value, arg: Any) { connection.reply(r, arg) } |
185 def reply(r: Reply.Value, arg: Any) { connection.reply(r, arg) } |
216 def notify(arg: Any) { connection.notify(arg) } |
186 def notify(arg: Any) { connection.notify(arg) } |
217 def message(kind: String, msg: String, more: JSON.Object.Entry*): Unit = |
187 def message(kind: String, msg: String, more: JSON.Object.Entry*): Unit = |
218 notify(Reply.message(msg, kind = kind) ++ more) |
188 notify(Reply.message(msg, kind = kind) ++ more) |
560 connection.read_message() match { |
530 connection.read_message() match { |
561 case None => finished = true |
531 case None => finished = true |
562 case Some("") => context.notify("Command 'help' provides list of commands") |
532 case Some("") => context.notify("Command 'help' provides list of commands") |
563 case Some(msg) => |
533 case Some(msg) => |
564 val (name, argument) = Server.Argument.split(msg) |
534 val (name, argument) = Server.Argument.split(msg) |
565 name match { |
535 Server.command_table.get(name) match { |
566 case Server.Command(cmd) => |
536 case Some(cmd) => |
567 argument match { |
537 argument match { |
568 case Server.Argument(arg) => |
538 case Server.Argument(arg) => |
569 if (cmd.isDefinedAt((context, arg))) { |
539 if (cmd.command_body.isDefinedAt((context, arg))) { |
570 Exn.capture { cmd((context, arg)) } match { |
540 Exn.capture { cmd.command_body((context, arg)) } match { |
571 case Exn.Res(task: Server.Task) => |
541 case Exn.Res(task: Server.Task) => |
572 connection.reply_ok(JSON.Object(task.ident)) |
542 connection.reply_ok(JSON.Object(task.ident)) |
573 task.start |
543 task.start |
574 case Exn.Res(res) => connection.reply_ok(res) |
544 case Exn.Res(res) => connection.reply_ok(res) |
575 case Exn.Exn(exn) => |
545 case Exn.Exn(exn) => |