text: from sublime_db.core.typecheck import List, Optional, Generator, Any, Callable, Dict
  
  import sublime
  import json
  import re
  from sublime_db import core
  from .adapter_configuration import AdapterConfiguration
  from .util import get_setting
  
  
  class Configuration:
  	def __init__(self, name: str, type: str, request: str, all: dict) -> None:
  		self.name = name
  		self.type = type
  		self.all = all
  		self.index = -1
  		self.request = request
  
  	@staticmethod
  	def from_json(json: dict) -> 'Configuration':
  		name = json.get('name')
  		assert name, 'expecting name for debug.configuration'
  		type = json.get('type')
  		assert type, 'expecting type for debug.configuration'
  		request = json.get('request')
  		assert request, 'expecting request for debug.configuration'
  		return Configuration(name, type, request, json)
  
  
  @core.async
  def add_configuration(window: sublime.Window, adapters: Dict[str, AdapterConfiguration]) -> core.awaitable[None]:
  	names = []
  	content = []
  	for name, adapter in adapters.items():
  		snippets = adapter.snippets
  		for snippet in adapter.snippets:
  			names.append(snippet.get('label', 'label'))
  			content.append(snippet.get('body', '{ snippet error: no body field}'))
  
  	names.append('Other: Custom')
  
  	index = yield from core.sublime_show_quick_panel_async(window, names, 0)
  	if index < 0:
  		return
  
  	if index >= len(content):
  		yield from insert_snippet(window, {'name': 'NAME', 'type': 'CUSTOM', 'request': 'attach'})
  	else:
  		yield from insert_snippet(window, content[index])
  
  
  def insert_snippet(window: sublime.Window, snippet: dict) -> core.awaitable[None]:
  	content = json.dumps(snippet, indent="\t")
  	content = content.replace('\\\\', '\\') # remove json encoded \ ...
  	project = window.project_file_name()
  	if project:
  		view = yield from core.sublime_open_file_async(window, project)
  		region = view.find('''"\s*debug.configurations\s*"\s*:\s*\[''', 0)
  		view.sel().clear()
  		view.sel().add(sublime.Region(region.b, region.b))
  		view.run_command('insert', {
  			'characters': '\n'
  		})
  		view.run_command('insert_snippet', {
  			'contents': content + ','
  		})
  	else:
  		sublime.set_clipboard(content)
  		core.display('Unable to insert configuration into sublime-project file: Copied to clipboard instead')
  
  
  @core.async
  def select_or_add_configuration(window: sublime.Window, index: Optional[int], configurations: List[Configuration], adapters: List[AdapterConfiguration]) -> core.awaitable[Optional[Configuration]]:
  	done = core.main_loop.create_future()
  	names = []
  	for c in configurations:
  		if index is not None and c.index == index:
  			names.append(c.name + ' ✓')
  		else:
  			names.append(c.name)
  
  	names.append("-- Add Configuration -- ")
  
  	selected_index = yield from core.sublime_show_quick_panel_async(window, names, index or 0)
  	if selected_index < 0:
  		return None
  	if selected_index >= len(configurations):
  		yield from add_configuration(window, adapters)
  		return None
  	return configurations[selected_index]
  